diff --git a/src/common/algorithm.h b/src/common/algorithm.h
index e21b1373ca..4804a3421c 100644
--- a/src/common/algorithm.h
+++ b/src/common/algorithm.h
@@ -15,7 +15,8 @@
 namespace Common {
 
 template <class ForwardIt, class T, class Compare = std::less<>>
-ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) {
+[[nodiscard]] ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value,
+                                   Compare comp = {}) {
     // Note: BOTH type T and the type after ForwardIt is dereferenced
     // must be implicitly convertible to BOTH Type1 and Type2, used in Compare.
     // This is stricter than lower_bound requirement (see above)
diff --git a/src/common/alignment.h b/src/common/alignment.h
index ef4d6f8964..5040043de9 100644
--- a/src/common/alignment.h
+++ b/src/common/alignment.h
@@ -9,7 +9,7 @@
 namespace Common {
 
 template <typename T>
-constexpr T AlignUp(T value, std::size_t size) {
+[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) {
     static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
     auto mod{static_cast<T>(value % size)};
     value -= mod;
@@ -17,31 +17,31 @@ constexpr T AlignUp(T value, std::size_t size) {
 }
 
 template <typename T>
-constexpr T AlignDown(T value, std::size_t size) {
+[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) {
     static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
     return static_cast<T>(value - value % size);
 }
 
 template <typename T>
-constexpr T AlignBits(T value, std::size_t align) {
+[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) {
     static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
     return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align);
 }
 
 template <typename T>
-constexpr bool Is4KBAligned(T value) {
+[[nodiscard]] constexpr bool Is4KBAligned(T value) {
     static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
     return (value & 0xFFF) == 0;
 }
 
 template <typename T>
-constexpr bool IsWordAligned(T value) {
+[[nodiscard]] constexpr bool IsWordAligned(T value) {
     static_assert(std::is_unsigned_v<T>, "T must be an unsigned value.");
     return (value & 0b11) == 0;
 }
 
 template <typename T>
-constexpr bool IsAligned(T value, std::size_t alignment) {
+[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) {
     using U = typename std::make_unsigned<T>::type;
     const U mask = static_cast<U>(alignment - 1);
     return (value & mask) == 0;
@@ -64,7 +64,7 @@ public:
     template <typename T2>
     constexpr AlignmentAllocator(const AlignmentAllocator<T2, Align>&) noexcept {}
 
-    T* allocate(size_type n) {
+    [[nodiscard]] T* allocate(size_type n) {
         return static_cast<T*>(::operator new (n * sizeof(T), std::align_val_t{Align}));
     }
 
diff --git a/src/common/atomic_ops.h b/src/common/atomic_ops.h
index 8d6b73c008..b468885893 100644
--- a/src/common/atomic_ops.h
+++ b/src/common/atomic_ops.h
@@ -8,10 +8,10 @@
 
 namespace Common {
 
-bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
-bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
-bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
-bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
-bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
+[[nodiscard]] bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
+[[nodiscard]] bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
+[[nodiscard]] bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
+[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
+[[nodiscard]] bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
 
 } // namespace Common
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 26ae6c7fc7..0f0661172c 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -36,13 +36,6 @@
 #include "common/common_funcs.h"
 #include "common/swap.h"
 
-// Inlining
-#ifdef _WIN32
-#define FORCE_INLINE __forceinline
-#else
-#define FORCE_INLINE inline __attribute__((always_inline))
-#endif
-
 /*
  * Abstract bitfield class
  *
@@ -142,8 +135,8 @@ public:
      * containing several bitfields can be assembled by formatting each of their values and ORing
      * the results together.
      */
-    static constexpr FORCE_INLINE StorageType FormatValue(const T& value) {
-        return ((StorageType)value << position) & mask;
+    [[nodiscard]] static constexpr StorageType FormatValue(const T& value) {
+        return (static_cast<StorageType>(value) << position) & mask;
     }
 
     /**
@@ -151,7 +144,7 @@ public:
      * (such as Value() or operator T), but this can be used to extract a value from a bitfield
      * union in a constexpr context.
      */
-    static constexpr FORCE_INLINE T ExtractValue(const StorageType& storage) {
+    [[nodiscard]] static constexpr T ExtractValue(const StorageType& storage) {
         if constexpr (std::numeric_limits<UnderlyingType>::is_signed) {
             std::size_t shift = 8 * sizeof(T) - bits;
             return static_cast<T>(static_cast<UnderlyingType>(storage << (shift - position)) >>
@@ -175,7 +168,7 @@ public:
     constexpr BitField(BitField&&) noexcept = default;
     constexpr BitField& operator=(BitField&&) noexcept = default;
 
-    constexpr operator T() const {
+    [[nodiscard]] constexpr operator T() const {
         return Value();
     }
 
@@ -183,11 +176,11 @@ public:
         storage = static_cast<StorageType>((storage & ~mask) | FormatValue(value));
     }
 
-    constexpr T Value() const {
+    [[nodiscard]] constexpr T Value() const {
         return ExtractValue(storage);
     }
 
-    constexpr explicit operator bool() const {
+    [[nodiscard]] constexpr explicit operator bool() const {
         return Value() != 0;
     }
 
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 6f7d5a9479..29f59a9a3e 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -17,12 +17,12 @@ namespace Common {
 
 /// Gets the size of a specified type T in bits.
 template <typename T>
-constexpr std::size_t BitSize() {
+[[nodiscard]] constexpr std::size_t BitSize() {
     return sizeof(T) * CHAR_BIT;
 }
 
 #ifdef _MSC_VER
-inline u32 CountLeadingZeroes32(u32 value) {
+[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
     unsigned long leading_zero = 0;
 
     if (_BitScanReverse(&leading_zero, value) != 0) {
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
     return 32;
 }
 
-inline u32 CountLeadingZeroes64(u64 value) {
+[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
     unsigned long leading_zero = 0;
 
     if (_BitScanReverse64(&leading_zero, value) != 0) {
@@ -42,7 +42,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
     return 64;
 }
 #else
-inline u32 CountLeadingZeroes32(u32 value) {
+[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) {
     if (value == 0) {
         return 32;
     }
@@ -50,7 +50,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
     return static_cast<u32>(__builtin_clz(value));
 }
 
-inline u32 CountLeadingZeroes64(u64 value) {
+[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) {
     if (value == 0) {
         return 64;
     }
@@ -60,7 +60,7 @@ inline u32 CountLeadingZeroes64(u64 value) {
 #endif
 
 #ifdef _MSC_VER
-inline u32 CountTrailingZeroes32(u32 value) {
+[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
     unsigned long trailing_zero = 0;
 
     if (_BitScanForward(&trailing_zero, value) != 0) {
@@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
     return 32;
 }
 
-inline u32 CountTrailingZeroes64(u64 value) {
+[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
     unsigned long trailing_zero = 0;
 
     if (_BitScanForward64(&trailing_zero, value) != 0) {
@@ -80,7 +80,7 @@ inline u32 CountTrailingZeroes64(u64 value) {
     return 64;
 }
 #else
-inline u32 CountTrailingZeroes32(u32 value) {
+[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) {
     if (value == 0) {
         return 32;
     }
@@ -88,7 +88,7 @@ inline u32 CountTrailingZeroes32(u32 value) {
     return static_cast<u32>(__builtin_ctz(value));
 }
 
-inline u32 CountTrailingZeroes64(u64 value) {
+[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) {
     if (value == 0) {
         return 64;
     }
@@ -99,13 +99,13 @@ inline u32 CountTrailingZeroes64(u64 value) {
 
 #ifdef _MSC_VER
 
-inline u32 MostSignificantBit32(const u32 value) {
+[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
     unsigned long result;
     _BitScanReverse(&result, value);
     return static_cast<u32>(result);
 }
 
-inline u32 MostSignificantBit64(const u64 value) {
+[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
     unsigned long result;
     _BitScanReverse64(&result, value);
     return static_cast<u32>(result);
@@ -113,30 +113,30 @@ inline u32 MostSignificantBit64(const u64 value) {
 
 #else
 
-inline u32 MostSignificantBit32(const u32 value) {
+[[nodiscard]] inline u32 MostSignificantBit32(const u32 value) {
     return 31U - static_cast<u32>(__builtin_clz(value));
 }
 
-inline u32 MostSignificantBit64(const u64 value) {
+[[nodiscard]] inline u32 MostSignificantBit64(const u64 value) {
     return 63U - static_cast<u32>(__builtin_clzll(value));
 }
 
 #endif
 
-inline u32 Log2Floor32(const u32 value) {
+[[nodiscard]] inline u32 Log2Floor32(const u32 value) {
     return MostSignificantBit32(value);
 }
 
-inline u32 Log2Ceil32(const u32 value) {
+[[nodiscard]] inline u32 Log2Ceil32(const u32 value) {
     const u32 log2_f = Log2Floor32(value);
     return log2_f + ((value ^ (1U << log2_f)) != 0U);
 }
 
-inline u32 Log2Floor64(const u64 value) {
+[[nodiscard]] inline u32 Log2Floor64(const u64 value) {
     return MostSignificantBit64(value);
 }
 
-inline u32 Log2Ceil64(const u64 value) {
+[[nodiscard]] inline u32 Log2Ceil64(const u64 value) {
     const u64 log2_f = static_cast<u64>(Log2Floor64(value));
     return static_cast<u32>(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL));
 }
diff --git a/src/common/cityhash.h b/src/common/cityhash.h
index 4b94f8e181..a00804e01e 100644
--- a/src/common/cityhash.h
+++ b/src/common/cityhash.h
@@ -61,42 +61,43 @@
 
 #pragma once
 
+#include <cstddef>
+#include <cstdint>
 #include <utility>
-#include <stdint.h>
-#include <stdlib.h> // for std::size_t.
 
 namespace Common {
 
-typedef std::pair<uint64_t, uint64_t> uint128;
+using uint128 = std::pair<uint64_t, uint64_t>;
 
-inline uint64_t Uint128Low64(const uint128& x) {
+[[nodiscard]] inline uint64_t Uint128Low64(const uint128& x) {
     return x.first;
 }
-inline uint64_t Uint128High64(const uint128& x) {
+[[nodiscard]] inline uint64_t Uint128High64(const uint128& x) {
     return x.second;
 }
 
 // Hash function for a byte array.
-uint64_t CityHash64(const char* buf, std::size_t len);
+[[nodiscard]] uint64_t CityHash64(const char* buf, std::size_t len);
 
 // Hash function for a byte array.  For convenience, a 64-bit seed is also
 // hashed into the result.
-uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
+[[nodiscard]] uint64_t CityHash64WithSeed(const char* buf, std::size_t len, uint64_t seed);
 
 // Hash function for a byte array.  For convenience, two seeds are also
 // hashed into the result.
-uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0, uint64_t seed1);
+[[nodiscard]] uint64_t CityHash64WithSeeds(const char* buf, std::size_t len, uint64_t seed0,
+                                           uint64_t seed1);
 
 // Hash function for a byte array.
-uint128 CityHash128(const char* s, std::size_t len);
+[[nodiscard]] uint128 CityHash128(const char* s, std::size_t len);
 
 // Hash function for a byte array.  For convenience, a 128-bit seed is also
 // hashed into the result.
-uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
+[[nodiscard]] uint128 CityHash128WithSeed(const char* s, std::size_t len, uint128 seed);
 
 // Hash 128 input bits down to 64 bits of output.
 // This is intended to be a reasonably good hash function.
-inline uint64_t Hash128to64(const uint128& x) {
+[[nodiscard]] inline uint64_t Hash128to64(const uint128& x) {
     // Murmur-inspired hashing.
     const uint64_t kMul = 0x9ddfea08eb382d69ULL;
     uint64_t a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
diff --git a/src/common/color.h b/src/common/color.h
index 3a2222077e..381d6332ef 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -13,42 +13,42 @@
 namespace Color {
 
 /// Convert a 1-bit color component to 8 bit
-constexpr u8 Convert1To8(u8 value) {
+[[nodiscard]] constexpr u8 Convert1To8(u8 value) {
     return value * 255;
 }
 
 /// Convert a 4-bit color component to 8 bit
-constexpr u8 Convert4To8(u8 value) {
+[[nodiscard]] constexpr u8 Convert4To8(u8 value) {
     return (value << 4) | value;
 }
 
 /// Convert a 5-bit color component to 8 bit
-constexpr u8 Convert5To8(u8 value) {
+[[nodiscard]] constexpr u8 Convert5To8(u8 value) {
     return (value << 3) | (value >> 2);
 }
 
 /// Convert a 6-bit color component to 8 bit
-constexpr u8 Convert6To8(u8 value) {
+[[nodiscard]] constexpr u8 Convert6To8(u8 value) {
     return (value << 2) | (value >> 4);
 }
 
 /// Convert a 8-bit color component to 1 bit
-constexpr u8 Convert8To1(u8 value) {
+[[nodiscard]] constexpr u8 Convert8To1(u8 value) {
     return value >> 7;
 }
 
 /// Convert a 8-bit color component to 4 bit
-constexpr u8 Convert8To4(u8 value) {
+[[nodiscard]] constexpr u8 Convert8To4(u8 value) {
     return value >> 4;
 }
 
 /// Convert a 8-bit color component to 5 bit
-constexpr u8 Convert8To5(u8 value) {
+[[nodiscard]] constexpr u8 Convert8To5(u8 value) {
     return value >> 3;
 }
 
 /// Convert a 8-bit color component to 6 bit
-constexpr u8 Convert8To6(u8 value) {
+[[nodiscard]] constexpr u8 Convert8To6(u8 value) {
     return value >> 2;
 }
 
@@ -57,7 +57,7 @@ constexpr u8 Convert8To6(u8 value) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
     return {bytes[3], bytes[2], bytes[1], bytes[0]};
 }
 
@@ -66,7 +66,7 @@ inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
     return {bytes[2], bytes[1], bytes[0], 255};
 }
 
@@ -75,7 +75,7 @@ inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
     return {bytes[1], bytes[0], 0, 255};
 }
 
@@ -84,7 +84,7 @@ inline Common::Vec4<u8> DecodeRG8(const u8* bytes) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
     u16_le pixel;
     std::memcpy(&pixel, bytes, sizeof(pixel));
     return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F),
@@ -96,7 +96,7 @@ inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
     u16_le pixel;
     std::memcpy(&pixel, bytes, sizeof(pixel));
     return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F),
@@ -108,7 +108,7 @@ inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) {
  * @param bytes Pointer to encoded source color
  * @return Result color decoded as Common::Vec4<u8>
  */
-inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
+[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
     u16_le pixel;
     std::memcpy(&pixel, bytes, sizeof(pixel));
     return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF),
@@ -120,7 +120,7 @@ inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) {
  * @param bytes Pointer to encoded source value
  * @return Depth value as an u32
  */
-inline u32 DecodeD16(const u8* bytes) {
+[[nodiscard]] inline u32 DecodeD16(const u8* bytes) {
     u16_le data;
     std::memcpy(&data, bytes, sizeof(data));
     return data;
@@ -131,7 +131,7 @@ inline u32 DecodeD16(const u8* bytes) {
  * @param bytes Pointer to encoded source value
  * @return Depth value as an u32
  */
-inline u32 DecodeD24(const u8* bytes) {
+[[nodiscard]] inline u32 DecodeD24(const u8* bytes) {
     return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0];
 }
 
@@ -140,7 +140,7 @@ inline u32 DecodeD24(const u8* bytes) {
  * @param bytes Pointer to encoded source values
  * @return Resulting values stored as a Common::Vec2
  */
-inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
+[[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) {
     return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]};
 }
 
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 88cf5250ad..98421bcedc 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -53,14 +53,14 @@ __declspec(dllimport) void __stdcall DebugBreak(void);
 // Call directly after the command or use the error num.
 // This function might change the error code.
 // Defined in Misc.cpp.
-std::string GetLastErrorMsg();
+[[nodiscard]] std::string GetLastErrorMsg();
 
 #define DECLARE_ENUM_FLAG_OPERATORS(type)                                                          \
-    constexpr type operator|(type a, type b) noexcept {                                            \
+    [[nodiscard]] constexpr type operator|(type a, type b) noexcept {                              \
         using T = std::underlying_type_t<type>;                                                    \
         return static_cast<type>(static_cast<T>(a) | static_cast<T>(b));                           \
     }                                                                                              \
-    constexpr type operator&(type a, type b) noexcept {                                            \
+    [[nodiscard]] constexpr type operator&(type a, type b) noexcept {                              \
         using T = std::underlying_type_t<type>;                                                    \
         return static_cast<type>(static_cast<T>(a) & static_cast<T>(b));                           \
     }                                                                                              \
@@ -74,22 +74,22 @@ std::string GetLastErrorMsg();
         a = static_cast<type>(static_cast<T>(a) & static_cast<T>(b));                              \
         return a;                                                                                  \
     }                                                                                              \
-    constexpr type operator~(type key) noexcept {                                                  \
+    [[nodiscard]] constexpr type operator~(type key) noexcept {                                    \
         using T = std::underlying_type_t<type>;                                                    \
         return static_cast<type>(~static_cast<T>(key));                                            \
     }                                                                                              \
-    constexpr bool True(type key) noexcept {                                                       \
+    [[nodiscard]] constexpr bool True(type key) noexcept {                                         \
         using T = std::underlying_type_t<type>;                                                    \
         return static_cast<T>(key) != 0;                                                           \
     }                                                                                              \
-    constexpr bool False(type key) noexcept {                                                      \
+    [[nodiscard]] constexpr bool False(type key) noexcept {                                        \
         using T = std::underlying_type_t<type>;                                                    \
         return static_cast<T>(key) == 0;                                                           \
     }
 
 namespace Common {
 
-constexpr u32 MakeMagic(char a, char b, char c, char d) {
+[[nodiscard]] constexpr u32 MakeMagic(char a, char b, char c, char d) {
     return u32(a) | u32(b) << 8 | u32(c) << 16 | u32(d) << 24;
 }
 
diff --git a/src/common/dynamic_library.h b/src/common/dynamic_library.h
index 2a06372fd8..3512da9402 100644
--- a/src/common/dynamic_library.h
+++ b/src/common/dynamic_library.h
@@ -33,7 +33,7 @@ public:
     ~DynamicLibrary();
 
     /// Returns the specified library name with the platform-specific suffix added.
-    static std::string GetUnprefixedFilename(const char* filename);
+    [[nodiscard]] static std::string GetUnprefixedFilename(const char* filename);
 
     /// Returns the specified library name in platform-specific format.
     /// Major/minor versions will not be included if set to -1.
@@ -41,28 +41,29 @@ public:
     /// Windows: LIBNAME-MAJOR-MINOR.dll
     /// Linux: libLIBNAME.so.MAJOR.MINOR
     /// Mac: libLIBNAME.MAJOR.MINOR.dylib
-    static std::string GetVersionedFilename(const char* libname, int major = -1, int minor = -1);
+    [[nodiscard]] static std::string GetVersionedFilename(const char* libname, int major = -1,
+                                                          int minor = -1);
 
     /// Returns true if a module is loaded, otherwise false.
-    bool IsOpen() const {
+    [[nodiscard]] bool IsOpen() const {
         return handle != nullptr;
     }
 
     /// Loads (or replaces) the handle with the specified library file name.
     /// Returns true if the library was loaded and can be used.
-    bool Open(const char* filename);
+    [[nodiscard]] bool Open(const char* filename);
 
     /// Unloads the library, any function pointers from this library are no longer valid.
     void Close();
 
     /// Returns the address of the specified symbol (function or variable) as an untyped pointer.
     /// If the specified symbol does not exist in this library, nullptr is returned.
-    void* GetSymbolAddress(const char* name) const;
+    [[nodiscard]] void* GetSymbolAddress(const char* name) const;
 
     /// Obtains the address of the specified symbol, automatically casting to the correct type.
     /// Returns true if the symbol was found and assigned, otherwise false.
     template <typename T>
-    bool GetSymbol(const char* name, T* ptr) const {
+    [[nodiscard]] bool GetSymbol(const char* name, T* ptr) const {
         *ptr = reinterpret_cast<T>(GetSymbolAddress(name));
         return *ptr != nullptr;
     }
diff --git a/src/common/fiber.h b/src/common/fiber.h
index dafc1100e5..89dde5e36f 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -47,7 +47,7 @@ public:
     /// Yields control from Fiber 'from' to Fiber 'to'
     /// Fiber 'from' must be the currently running fiber.
     static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to);
-    static std::shared_ptr<Fiber> ThreadToFiber();
+    [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
 
     void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter);
 
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 187b93161c..681b281373 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -48,19 +48,19 @@ struct FSTEntry {
 };
 
 // Returns true if file filename exists
-bool Exists(const std::string& filename);
+[[nodiscard]] bool Exists(const std::string& filename);
 
 // Returns true if filename is a directory
-bool IsDirectory(const std::string& filename);
+[[nodiscard]] bool IsDirectory(const std::string& filename);
 
 // Returns the size of filename (64bit)
-u64 GetSize(const std::string& filename);
+[[nodiscard]] u64 GetSize(const std::string& filename);
 
 // Overloaded GetSize, accepts file descriptor
-u64 GetSize(const int fd);
+[[nodiscard]] u64 GetSize(int fd);
 
 // Overloaded GetSize, accepts FILE*
-u64 GetSize(FILE* f);
+[[nodiscard]] u64 GetSize(FILE* f);
 
 // Returns true if successful, or path already exists.
 bool CreateDir(const std::string& filename);
@@ -120,7 +120,7 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
 bool DeleteDirRecursively(const std::string& directory, unsigned int recursion = 256);
 
 // Returns the current directory
-std::optional<std::string> GetCurrentDir();
+[[nodiscard]] std::optional<std::string> GetCurrentDir();
 
 // Create directory and copy contents (does not overwrite existing files)
 void CopyDir(const std::string& source_path, const std::string& dest_path);
@@ -132,20 +132,20 @@ bool SetCurrentDir(const std::string& directory);
 // directory. To be used in "multi-user" mode (that is, installed).
 const std::string& GetUserPath(UserPath path, const std::string& new_path = "");
 
-std::string GetHactoolConfigurationPath();
+[[nodiscard]] std::string GetHactoolConfigurationPath();
 
-std::string GetNANDRegistrationDir(bool system = false);
+[[nodiscard]] std::string GetNANDRegistrationDir(bool system = false);
 
 // Returns the path to where the sys file are
-std::string GetSysDirectory();
+[[nodiscard]] std::string GetSysDirectory();
 
 #ifdef __APPLE__
-std::string GetBundleDirectory();
+[[nodiscard]] std::string GetBundleDirectory();
 #endif
 
 #ifdef _WIN32
-const std::string& GetExeDirectory();
-std::string AppDataRoamingDirectory();
+[[nodiscard]] const std::string& GetExeDirectory();
+[[nodiscard]] std::string AppDataRoamingDirectory();
 #endif
 
 std::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
 
 // Splits the path on '/' or '\' and put the components into a vector
 // i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
-std::vector<std::string> SplitPathComponents(std::string_view filename);
+[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
 
 // Gets all of the text up to the last '/' or '\' in the path.
-std::string_view GetParentPath(std::string_view path);
+[[nodiscard]] std::string_view GetParentPath(std::string_view path);
 
 // Gets all of the text after the first '/' or '\' in the path.
-std::string_view GetPathWithoutTop(std::string_view path);
+[[nodiscard]] std::string_view GetPathWithoutTop(std::string_view path);
 
 // Gets the filename of the path
-std::string_view GetFilename(std::string_view path);
+[[nodiscard]] std::string_view GetFilename(std::string_view path);
 
 // Gets the extension of the filename
-std::string_view GetExtensionFromFilename(std::string_view name);
+[[nodiscard]] std::string_view GetExtensionFromFilename(std::string_view name);
 
 // Removes the final '/' or '\' if one exists
-std::string_view RemoveTrailingSlash(std::string_view path);
+[[nodiscard]] std::string_view RemoveTrailingSlash(std::string_view path);
 
 // Creates a new vector containing indices [first, last) from the original.
 template <typename T>
-std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first, std::size_t last) {
-    if (first >= last)
+[[nodiscard]] std::vector<T> SliceVector(const std::vector<T>& vector, std::size_t first,
+                                         std::size_t last) {
+    if (first >= last) {
         return {};
+    }
     last = std::min<std::size_t>(last, vector.size());
     return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
 }
 
-enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
+enum class DirectorySeparator {
+    ForwardSlash,
+    BackwardSlash,
+    PlatformDefault,
+};
 
 // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
 // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
-std::string SanitizePath(std::string_view path,
-                         DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
+[[nodiscard]] std::string SanitizePath(
+    std::string_view path,
+    DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
 
 // simple wrapper for cstdlib file functions to
 // hopefully will make error checking easier
@@ -215,7 +222,7 @@ public:
 
     void Swap(IOFile& other) noexcept;
 
-    bool Open(const std::string& filename, const char openmode[], int flags = 0);
+    [[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0);
     bool Close();
 
     template <typename T>
@@ -256,13 +263,13 @@ public:
         return WriteArray(str.data(), str.length());
     }
 
-    bool IsOpen() const {
+    [[nodiscard]] bool IsOpen() const {
         return nullptr != m_file;
     }
 
     bool Seek(s64 off, int origin) const;
-    u64 Tell() const;
-    u64 GetSize() const;
+    [[nodiscard]] u64 Tell() const;
+    [[nodiscard]] u64 GetSize() const;
     bool Resize(u64 size);
     bool Flush();
 
diff --git a/src/common/hash.h b/src/common/hash.h
index b2538f3ea0..2989307029 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -5,36 +5,11 @@
 #pragma once
 
 #include <cstddef>
-#include <cstring>
 #include <utility>
 #include <boost/functional/hash.hpp>
-#include "common/cityhash.h"
-#include "common/common_types.h"
 
 namespace Common {
 
-/**
- * Computes a 64-bit hash over the specified block of data
- * @param data Block of data to compute hash over
- * @param len Length of data (in bytes) to compute hash over
- * @returns 64-bit hash value that was computed over the data block
- */
-static inline u64 ComputeHash64(const void* data, std::size_t len) {
-    return CityHash64(static_cast<const char*>(data), len);
-}
-
-/**
- * Computes a 64-bit hash of a struct. In addition to being trivially copyable, it is also critical
- * that either the struct includes no padding, or that any padding is initialized to a known value
- * by memsetting the struct to 0 before filling it in.
- */
-template <typename T>
-static inline u64 ComputeStructHash64(const T& data) {
-    static_assert(std::is_trivially_copyable_v<T>,
-                  "Type passed to ComputeStructHash64 must be trivially copyable");
-    return ComputeHash64(&data, sizeof(data));
-}
-
 struct PairHash {
     template <class T1, class T2>
     std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index a0a0e78a47..120f1a5e64 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -14,7 +14,7 @@
 
 namespace Common {
 
-constexpr u8 ToHexNibble(char c) {
+[[nodiscard]] constexpr u8 ToHexNibble(char c) {
     if (c >= 65 && c <= 70) {
         return c - 55;
     }
@@ -26,10 +26,10 @@ constexpr u8 ToHexNibble(char c) {
     return c - 48;
 }
 
-std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
+[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
 
 template <std::size_t Size, bool le = false>
-constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
+[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
     std::array<u8, Size> out{};
     if constexpr (le) {
         for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
@@ -44,7 +44,7 @@ constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
 }
 
 template <typename ContiguousContainer>
-std::string HexToString(const ContiguousContainer& data, bool upper = true) {
+[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
     static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
                   "Underlying type within the contiguous container must be u8.");
 
@@ -60,11 +60,11 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
     return out;
 }
 
-constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
+[[nodiscard]] constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
     return HexStringToArray<16>(data);
 }
 
-constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
+[[nodiscard]] constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
     return HexStringToArray<32>(data);
 }
 
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
index 173f9b9ad7..088ff5c917 100644
--- a/src/common/lz4_compression.h
+++ b/src/common/lz4_compression.h
@@ -18,7 +18,7 @@ namespace Common::Compression {
  *
  * @return the compressed data.
  */
-std::vector<u8> CompressDataLZ4(std::span<const u8> source);
+[[nodiscard]] std::vector<u8> CompressDataLZ4(std::span<const u8> source);
 
 /**
  * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
@@ -31,7 +31,7 @@ std::vector<u8> CompressDataLZ4(std::span<const u8> source);
  *
  * @return the compressed data.
  */
-std::vector<u8> CompressDataLZ4HC(std::span<const u8> source, s32 compression_level);
+[[nodiscard]] std::vector<u8> CompressDataLZ4HC(std::span<const u8> source, s32 compression_level);
 
 /**
  * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
@@ -40,7 +40,7 @@ std::vector<u8> CompressDataLZ4HC(std::span<const u8> source, s32 compression_le
  *
  * @return the compressed data.
  */
-std::vector<u8> CompressDataLZ4HCMax(std::span<const u8> source);
+[[nodiscard]] std::vector<u8> CompressDataLZ4HCMax(std::span<const u8> source);
 
 /**
  * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
@@ -50,6 +50,7 @@ std::vector<u8> CompressDataLZ4HCMax(std::span<const u8> source);
  *
  * @return the decompressed data.
  */
-std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size);
+[[nodiscard]] std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
+                                                std::size_t uncompressed_size);
 
 } // namespace Common::Compression
\ No newline at end of file
diff --git a/src/common/math_util.h b/src/common/math_util.h
index abca3177c5..cc35c90ee4 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -23,7 +23,7 @@ struct Rectangle {
     constexpr Rectangle(T left, T top, T right, T bottom)
         : left(left), top(top), right(right), bottom(bottom) {}
 
-    T GetWidth() const {
+    [[nodiscard]] T GetWidth() const {
         if constexpr (std::is_floating_point_v<T>) {
             return std::abs(right - left);
         } else {
@@ -31,7 +31,7 @@ struct Rectangle {
         }
     }
 
-    T GetHeight() const {
+    [[nodiscard]] T GetHeight() const {
         if constexpr (std::is_floating_point_v<T>) {
             return std::abs(bottom - top);
         } else {
@@ -39,15 +39,15 @@ struct Rectangle {
         }
     }
 
-    Rectangle<T> TranslateX(const T x) const {
+    [[nodiscard]] Rectangle<T> TranslateX(const T x) const {
         return Rectangle{left + x, top, right + x, bottom};
     }
 
-    Rectangle<T> TranslateY(const T y) const {
+    [[nodiscard]] Rectangle<T> TranslateY(const T y) const {
         return Rectangle{left, top + y, right, bottom + y};
     }
 
-    Rectangle<T> Scale(const float s) const {
+    [[nodiscard]] Rectangle<T> Scale(const float s) const {
         return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
                          static_cast<T>(top + GetHeight() * s)};
     }
diff --git a/src/common/memory_detect.h b/src/common/memory_detect.h
index a73c0f3f4c..0f73751c8f 100644
--- a/src/common/memory_detect.h
+++ b/src/common/memory_detect.h
@@ -17,6 +17,6 @@ struct MemoryInfo {
  * Gets the memory info of the host system
  * @return Reference to a MemoryInfo struct with the physical and swap memory sizes in bytes
  */
-const MemoryInfo& GetMemInfo();
+[[nodiscard]] const MemoryInfo& GetMemInfo();
 
 } // 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 50acfdbf2f..4b305bf409 100644
--- a/src/common/multi_level_queue.h
+++ b/src/common/multi_level_queue.h
@@ -223,15 +223,15 @@ public:
         ListShiftForward(levels[priority], n);
     }
 
-    std::size_t depth() const {
+    [[nodiscard]] std::size_t depth() const {
         return Depth;
     }
 
-    std::size_t size(u32 priority) const {
+    [[nodiscard]] std::size_t size(u32 priority) const {
         return levels[priority].size();
     }
 
-    std::size_t size() const {
+    [[nodiscard]] std::size_t size() const {
         u64 priorities = used_priorities;
         std::size_t size = 0;
         while (priorities != 0) {
@@ -242,64 +242,64 @@ public:
         return size;
     }
 
-    bool empty() const {
+    [[nodiscard]] bool empty() const {
         return used_priorities == 0;
     }
 
-    bool empty(u32 priority) const {
+    [[nodiscard]] bool empty(u32 priority) const {
         return (used_priorities & (1ULL << priority)) == 0;
     }
 
-    u32 highest_priority_set(u32 max_priority = 0) const {
+    [[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
         const u64 priorities =
             max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
         return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
     }
 
-    u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
+    [[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
         const u64 priorities = min_priority >= Depth - 1
                                    ? used_priorities
                                    : (used_priorities & ((1ULL << (min_priority + 1)) - 1));
         return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
     }
 
-    const_iterator cbegin(u32 max_prio = 0) const {
+    [[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
         const u32 priority = highest_priority_set(max_prio);
         return priority == Depth ? cend()
                                  : const_iterator{*this, levels[priority].cbegin(), priority};
     }
-    const_iterator begin(u32 max_prio = 0) const {
+    [[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
         return cbegin(max_prio);
     }
-    iterator begin(u32 max_prio = 0) {
+    [[nodiscard]] iterator begin(u32 max_prio = 0) {
         const u32 priority = highest_priority_set(max_prio);
         return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
     }
 
-    const_iterator cend(u32 min_prio = Depth - 1) const {
+    [[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
         return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
     }
-    const_iterator end(u32 min_prio = Depth - 1) const {
+    [[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
         return cend(min_prio);
     }
-    iterator end(u32 min_prio = Depth - 1) {
+    [[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
         return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
     }
 
-    T& front(u32 max_priority = 0) {
+    [[nodiscard]] T& front(u32 max_priority = 0) {
         const u32 priority = highest_priority_set(max_priority);
         return levels[priority == Depth ? 0 : priority].front();
     }
-    const T& front(u32 max_priority = 0) const {
+    [[nodiscard]] const T& front(u32 max_priority = 0) const {
         const u32 priority = highest_priority_set(max_priority);
         return levels[priority == Depth ? 0 : priority].front();
     }
 
-    T back(u32 min_priority = Depth - 1) {
+    [[nodiscard]] T& back(u32 min_priority = Depth - 1) {
         const u32 priority = lowest_priority_set(min_priority); // intended
         return levels[priority == Depth ? 63 : priority].back();
     }
-    const T& back(u32 min_priority = Depth - 1) const {
+    [[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
         const u32 priority = lowest_priority_set(min_priority); // intended
         return levels[priority == Depth ? 63 : priority].back();
     }
@@ -329,7 +329,8 @@ private:
         in_list.splice(position, out_list, element);
     }
 
-    static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) {
+    [[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
+                                                           const T& element) {
         auto it = list.cbegin();
         while (it != list.cend() && *it != element) {
             ++it;
diff --git a/src/common/page_table.h b/src/common/page_table.h
index 1e8bd3187e..cf5eed780d 100644
--- a/src/common/page_table.h
+++ b/src/common/page_table.h
@@ -36,11 +36,11 @@ struct SpecialRegion {
 
     MemoryHookPointer handler;
 
-    bool operator<(const SpecialRegion& other) const {
+    [[nodiscard]] bool operator<(const SpecialRegion& other) const {
         return std::tie(type, handler) < std::tie(other.type, other.handler);
     }
 
-    bool operator==(const SpecialRegion& other) const {
+    [[nodiscard]] bool operator==(const SpecialRegion& other) const {
         return std::tie(type, handler) == std::tie(other.type, other.handler);
     }
 };
diff --git a/src/common/param_package.h b/src/common/param_package.h
index 6a0a9b6564..c8a70bfa95 100644
--- a/src/common/param_package.h
+++ b/src/common/param_package.h
@@ -24,14 +24,14 @@ public:
     ParamPackage& operator=(const ParamPackage& other) = default;
     ParamPackage& operator=(ParamPackage&& other) = default;
 
-    std::string Serialize() const;
-    std::string Get(const std::string& key, const std::string& default_value) const;
-    int Get(const std::string& key, int default_value) const;
-    float Get(const std::string& key, float default_value) const;
+    [[nodiscard]] std::string Serialize() const;
+    [[nodiscard]] std::string Get(const std::string& key, const std::string& default_value) const;
+    [[nodiscard]] int Get(const std::string& key, int default_value) const;
+    [[nodiscard]] float Get(const std::string& key, float default_value) const;
     void Set(const std::string& key, std::string value);
     void Set(const std::string& key, int value);
     void Set(const std::string& key, float value);
-    bool Has(const std::string& key) const;
+    [[nodiscard]] bool Has(const std::string& key) const;
     void Erase(const std::string& key);
     void Clear();
 
diff --git a/src/common/quaternion.h b/src/common/quaternion.h
index 370198ae0f..da44f35cdc 100644
--- a/src/common/quaternion.h
+++ b/src/common/quaternion.h
@@ -14,35 +14,36 @@ public:
     Vec3<T> xyz;
     T w{};
 
-    Quaternion<decltype(-T{})> Inverse() const {
+    [[nodiscard]] Quaternion<decltype(-T{})> Inverse() const {
         return {-xyz, w};
     }
 
-    Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
+    [[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
         return {xyz + other.xyz, w + other.w};
     }
 
-    Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
+    [[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
         return {xyz - other.xyz, w - other.w};
     }
 
-    Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(const Quaternion& other) const {
+    [[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
+        const Quaternion& other) const {
         return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
                 w * other.w - Dot(xyz, other.xyz)};
     }
 
-    Quaternion<T> Normalized() const {
+    [[nodiscard]] Quaternion<T> Normalized() const {
         T length = std::sqrt(xyz.Length2() + w * w);
         return {xyz / length, w / length};
     }
 };
 
 template <typename T>
-auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
+[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
     return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
 }
 
-inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
+[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
     return {axis * std::sin(angle / 2), std::cos(angle / 2)};
 }
 
diff --git a/src/common/ring_buffer.h b/src/common/ring_buffer.h
index abe3b4dc2e..138fa01310 100644
--- a/src/common/ring_buffer.h
+++ b/src/common/ring_buffer.h
@@ -91,12 +91,12 @@ public:
     }
 
     /// @returns Number of slots used
-    std::size_t Size() const {
+    [[nodiscard]] std::size_t Size() const {
         return m_write_index.load() - m_read_index.load();
     }
 
     /// @returns Maximum size of ring buffer
-    constexpr std::size_t Capacity() const {
+    [[nodiscard]] constexpr std::size_t Capacity() const {
         return capacity;
     }
 
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h
index 1df5528c47..4f946a2582 100644
--- a/src/common/spin_lock.h
+++ b/src/common/spin_lock.h
@@ -17,7 +17,7 @@ class SpinLock {
 public:
     void lock();
     void unlock();
-    bool try_lock();
+    [[nodiscard]] bool try_lock();
 
 private:
     std::atomic_flag lck = ATOMIC_FLAG_INIT;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 023dff5dca..a32c07c062 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -12,19 +12,19 @@
 namespace Common {
 
 /// Make a string lowercase
-std::string ToLower(std::string str);
+[[nodiscard]] std::string ToLower(std::string str);
 
 /// Make a string uppercase
-std::string ToUpper(std::string str);
+[[nodiscard]] std::string ToUpper(std::string str);
 
-std::string StringFromBuffer(const std::vector<u8>& data);
+[[nodiscard]] std::string StringFromBuffer(const std::vector<u8>& data);
 
-std::string StripSpaces(const std::string& s);
-std::string StripQuotes(const std::string& s);
+[[nodiscard]] std::string StripSpaces(const std::string& s);
+[[nodiscard]] std::string StripQuotes(const std::string& s);
 
-std::string StringFromBool(bool value);
+[[nodiscard]] std::string StringFromBool(bool value);
 
-std::string TabsToSpaces(int tab_size, std::string in);
+[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
 
 void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
 
@@ -34,14 +34,15 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
 
 void BuildCompleteFilename(std::string& _CompleteFilename, const std::string& _Path,
                            const std::string& _Filename);
-std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest);
+[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
+                                     const std::string& dest);
 
-std::string UTF16ToUTF8(const std::u16string& input);
-std::u16string UTF8ToUTF16(const std::string& input);
+[[nodiscard]] std::string UTF16ToUTF8(const std::u16string& input);
+[[nodiscard]] std::u16string UTF8ToUTF16(const std::string& input);
 
 #ifdef _WIN32
-std::string UTF16ToUTF8(const std::wstring& input);
-std::wstring UTF8ToUTF16W(const std::string& str);
+[[nodiscard]] std::string UTF16ToUTF8(const std::wstring& input);
+[[nodiscard]] std::wstring UTF8ToUTF16W(const std::string& str);
 
 #endif
 
@@ -50,7 +51,7 @@ std::wstring UTF8ToUTF16W(const std::string& str);
  * `other` for equality.
  */
 template <typename InIt>
-bool ComparePartialString(InIt begin, InIt end, const char* other) {
+[[nodiscard]] bool ComparePartialString(InIt begin, InIt end, const char* other) {
     for (; begin != end && *other != '\0'; ++begin, ++other) {
         if (*begin != *other) {
             return false;
@@ -64,14 +65,15 @@ bool ComparePartialString(InIt begin, InIt end, const char* other) {
  * Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
  * NUL-terminated then the string ends at max_len characters.
  */
-std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t max_len);
+[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(const char* buffer,
+                                                              std::size_t max_len);
 
 /**
  * Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
  * null-terminated, then the string ends at the greatest multiple of two less then or equal to
  * max_len_bytes.
  */
-std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
-                                                        std::size_t max_len);
+[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
+                                                                      std::size_t max_len);
 
 } // namespace Common
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index 854a73fae7..4aa299f9a8 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -63,30 +63,30 @@ public:
 
     void Accept(VisitorInterface& visitor) const override;
 
-    const std::string& GetName() const override {
+    [[nodiscard]] const std::string& GetName() const override {
         return name;
     }
 
     /**
      * Returns the type of the field.
      */
-    FieldType GetType() const {
+    [[nodiscard]] FieldType GetType() const {
         return type;
     }
 
     /**
      * Returns the value of the field.
      */
-    const T& GetValue() const {
+    [[nodiscard]] const T& GetValue() const {
         return value;
     }
 
-    bool operator==(const Field& other) const {
+    [[nodiscard]] bool operator==(const Field& other) const {
         return (type == other.type) && (name == other.name) && (value == other.value);
     }
 
-    bool operator!=(const Field& other) const {
-        return !(*this == other);
+    [[nodiscard]] bool operator!=(const Field& other) const {
+        return !operator==(other);
     }
 
 private:
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 791f99a8c5..def9e5d8d1 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -18,14 +18,14 @@ struct ThreadQueueList {
     using Priority = unsigned int;
 
     // Number of priority levels. (Valid levels are [0..NUM_QUEUES).)
-    static const Priority NUM_QUEUES = N;
+    static constexpr Priority NUM_QUEUES = N;
 
     ThreadQueueList() {
         first = nullptr;
     }
 
     // Only for debugging, returns priority level.
-    Priority contains(const T& uid) const {
+    [[nodiscard]] Priority contains(const T& uid) const {
         for (Priority i = 0; i < NUM_QUEUES; ++i) {
             const Queue& cur = queues[i];
             if (std::find(cur.data.cbegin(), cur.data.cend(), uid) != cur.data.cend()) {
@@ -36,7 +36,7 @@ struct ThreadQueueList {
         return -1;
     }
 
-    T get_first() const {
+    [[nodiscard]] T get_first() const {
         const Queue* cur = first;
         while (cur != nullptr) {
             if (!cur->data.empty()) {
@@ -49,7 +49,7 @@ struct ThreadQueueList {
     }
 
     template <typename UnaryPredicate>
-    T get_first_filter(UnaryPredicate filter) const {
+    [[nodiscard]] T get_first_filter(UnaryPredicate filter) const {
         const Queue* cur = first;
         while (cur != nullptr) {
             if (!cur->data.empty()) {
@@ -129,7 +129,7 @@ struct ThreadQueueList {
         first = nullptr;
     }
 
-    bool empty(Priority priority) const {
+    [[nodiscard]] bool empty(Priority priority) const {
         const Queue* cur = &queues[priority];
         return cur->data.empty();
     }
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index 8268bbd5c8..a4647314a7 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -25,15 +25,15 @@ public:
         delete read_ptr;
     }
 
-    std::size_t Size() const {
+    [[nodiscard]] std::size_t Size() const {
         return size.load();
     }
 
-    bool Empty() const {
+    [[nodiscard]] bool Empty() const {
         return Size() == 0;
     }
 
-    T& Front() const {
+    [[nodiscard]] T& Front() const {
         return read_ptr->current;
     }
 
@@ -130,15 +130,15 @@ private:
 template <typename T>
 class MPSCQueue {
 public:
-    std::size_t Size() const {
+    [[nodiscard]] std::size_t Size() const {
         return spsc_queue.Size();
     }
 
-    bool Empty() const {
+    [[nodiscard]] bool Empty() const {
         return spsc_queue.Empty();
     }
 
-    T& Front() const {
+    [[nodiscard]] T& Front() const {
         return spsc_queue.Front();
     }
 
diff --git a/src/common/time_zone.h b/src/common/time_zone.h
index 945daa09ce..9f5939ca50 100644
--- a/src/common/time_zone.h
+++ b/src/common/time_zone.h
@@ -10,9 +10,9 @@
 namespace Common::TimeZone {
 
 /// Gets the default timezone, i.e. "GMT"
-std::string GetDefaultTimeZone();
+[[nodiscard]] std::string GetDefaultTimeZone();
 
 /// Gets the offset of the current timezone (from the default), in seconds
-std::chrono::seconds GetCurrentOffsetSeconds();
+[[nodiscard]] std::chrono::seconds GetCurrentOffsetSeconds();
 
 } // namespace Common::TimeZone
diff --git a/src/common/timer.h b/src/common/timer.h
index 27b521baac..8894a143d1 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -19,18 +19,18 @@ public:
 
     // The time difference is always returned in milliseconds, regardless of alternative internal
     // representation
-    std::chrono::milliseconds GetTimeDifference();
+    [[nodiscard]] std::chrono::milliseconds GetTimeDifference();
     void AddTimeDifference();
 
-    static std::chrono::seconds GetTimeSinceJan1970();
-    static std::chrono::seconds GetLocalTimeSinceJan1970();
-    static double GetDoubleTime();
+    [[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970();
+    [[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970();
+    [[nodiscard]] static double GetDoubleTime();
 
-    static std::string GetTimeFormatted();
-    std::string GetTimeElapsedFormatted() const;
-    std::chrono::milliseconds GetTimeElapsed();
+    [[nodiscard]] static std::string GetTimeFormatted();
+    [[nodiscard]] std::string GetTimeElapsedFormatted() const;
+    [[nodiscard]] std::chrono::milliseconds GetTimeElapsed();
 
-    static std::chrono::milliseconds GetTimeMs();
+    [[nodiscard]] static std::chrono::milliseconds GetTimeMs();
 
 private:
     std::chrono::milliseconds m_LastTime;
diff --git a/src/common/uint128.h b/src/common/uint128.h
index 503cd2d0c6..969259ab6c 100644
--- a/src/common/uint128.h
+++ b/src/common/uint128.h
@@ -10,13 +10,13 @@
 namespace Common {
 
 // This function multiplies 2 u64 values and divides it by a u64 value.
-u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
+[[nodiscard]] u64 MultiplyAndDivide64(u64 a, u64 b, u64 d);
 
 // This function multiplies 2 u64 values and produces a u128 value;
-u128 Multiply64Into128(u64 a, u64 b);
+[[nodiscard]] u128 Multiply64Into128(u64 a, u64 b);
 
 // This function divides a u128 by a u32 value and produces two u64 values:
 // the result of division and the remainder
-std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
+[[nodiscard]] std::pair<u64, u64> Divide128On32(u128 dividend, u32 divisor);
 
 } // namespace Common
diff --git a/src/common/uuid.h b/src/common/uuid.h
index 4d3af8cec6..4ab9a25f0d 100644
--- a/src/common/uuid.h
+++ b/src/common/uuid.h
@@ -19,21 +19,21 @@ struct UUID {
     constexpr explicit UUID(const u128& id) : uuid{id} {}
     constexpr explicit UUID(const u64 lo, const u64 hi) : uuid{{lo, hi}} {}
 
-    constexpr explicit operator bool() const {
+    [[nodiscard]] constexpr explicit operator bool() const {
         return uuid[0] != INVALID_UUID[0] && uuid[1] != INVALID_UUID[1];
     }
 
-    constexpr bool operator==(const UUID& rhs) const {
+    [[nodiscard]] constexpr bool operator==(const UUID& rhs) const {
         // TODO(DarkLordZach): Replace with uuid == rhs.uuid with C++20
         return uuid[0] == rhs.uuid[0] && uuid[1] == rhs.uuid[1];
     }
 
-    constexpr bool operator!=(const UUID& rhs) const {
+    [[nodiscard]] constexpr bool operator!=(const UUID& rhs) const {
         return !operator==(rhs);
     }
 
     // TODO(ogniK): Properly generate uuids based on RFC-4122
-    static UUID Generate();
+    [[nodiscard]] static UUID Generate();
 
     // Set the UUID to {0,0} to be considered an invalid user
     constexpr void Invalidate() {
@@ -41,12 +41,12 @@ struct UUID {
     }
 
     // TODO(ogniK): Properly generate a Nintendo ID
-    constexpr u64 GetNintendoID() const {
+    [[nodiscard]] constexpr u64 GetNintendoID() const {
         return uuid[0];
     }
 
-    std::string Format() const;
-    std::string FormatSwitch() const;
+    [[nodiscard]] std::string Format() const;
+    [[nodiscard]] std::string FormatSwitch() const;
 };
 static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
 
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 4294853296..2a0fcf5414 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -52,15 +52,15 @@ public:
     constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
 
     template <typename T2>
-    constexpr Vec2<T2> Cast() const {
+    [[nodiscard]] constexpr Vec2<T2> Cast() const {
         return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
     }
 
-    static constexpr Vec2 AssignToAll(const T& f) {
+    [[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) {
         return Vec2{f, f};
     }
 
-    constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
+    [[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
         return {x + other.x, y + other.y};
     }
     constexpr Vec2& operator+=(const Vec2& other) {
@@ -68,7 +68,7 @@ public:
         y += other.y;
         return *this;
     }
-    constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
+    [[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
         return {x - other.x, y - other.y};
     }
     constexpr Vec2& operator-=(const Vec2& other) {
@@ -78,15 +78,15 @@ public:
     }
 
     template <typename U = T>
-    constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+    [[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
         return {-x, -y};
     }
-    constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
+    [[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
         return {x * other.x, y * other.y};
     }
 
     template <typename V>
-    constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
+    [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
         return {x * f, y * f};
     }
 
@@ -97,7 +97,7 @@ public:
     }
 
     template <typename V>
-    constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
+    [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
         return {x / f, y / f};
     }
 
@@ -107,18 +107,18 @@ public:
         return *this;
     }
 
-    constexpr T Length2() const {
+    [[nodiscard]] constexpr T Length2() const {
         return x * x + y * y;
     }
 
     // Only implemented for T=float
-    float Length() const;
-    float Normalize(); // returns the previous length, which is often useful
+    [[nodiscard]] float Length() const;
+    [[nodiscard]] float Normalize(); // returns the previous length, which is often useful
 
-    constexpr T& operator[](std::size_t i) {
+    [[nodiscard]] constexpr T& operator[](std::size_t i) {
         return *((&x) + i);
     }
-    constexpr const T& operator[](std::size_t i) const {
+    [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
         return *((&x) + i);
     }
 
@@ -128,46 +128,46 @@ public:
     }
 
     // Common aliases: UV (texel coordinates), ST (texture coordinates)
-    constexpr T& u() {
+    [[nodiscard]] constexpr T& u() {
         return x;
     }
-    constexpr T& v() {
+    [[nodiscard]] constexpr T& v() {
         return y;
     }
-    constexpr T& s() {
+    [[nodiscard]] constexpr T& s() {
         return x;
     }
-    constexpr T& t() {
+    [[nodiscard]] constexpr T& t() {
         return y;
     }
 
-    constexpr const T& u() const {
+    [[nodiscard]] constexpr const T& u() const {
         return x;
     }
-    constexpr const T& v() const {
+    [[nodiscard]] constexpr const T& v() const {
         return y;
     }
-    constexpr const T& s() const {
+    [[nodiscard]] constexpr const T& s() const {
         return x;
     }
-    constexpr const T& t() const {
+    [[nodiscard]] constexpr const T& t() const {
         return y;
     }
 
     // swizzlers - create a subvector of specific components
-    constexpr Vec2 yx() const {
+    [[nodiscard]] constexpr Vec2 yx() const {
         return Vec2(y, x);
     }
-    constexpr Vec2 vu() const {
+    [[nodiscard]] constexpr Vec2 vu() const {
         return Vec2(y, x);
     }
-    constexpr Vec2 ts() const {
+    [[nodiscard]] constexpr Vec2 ts() const {
         return Vec2(y, x);
     }
 };
 
 template <typename T, typename V>
-constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
+[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
     return Vec2<T>(f * vec.x, f * vec.y);
 }
 
@@ -196,15 +196,15 @@ public:
     constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
 
     template <typename T2>
-    constexpr Vec3<T2> Cast() const {
+    [[nodiscard]] constexpr Vec3<T2> Cast() const {
         return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
     }
 
-    static constexpr Vec3 AssignToAll(const T& f) {
+    [[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) {
         return Vec3(f, f, f);
     }
 
-    constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
+    [[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
         return {x + other.x, y + other.y, z + other.z};
     }
 
@@ -215,7 +215,7 @@ public:
         return *this;
     }
 
-    constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
+    [[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
         return {x - other.x, y - other.y, z - other.z};
     }
 
@@ -227,16 +227,16 @@ public:
     }
 
     template <typename U = T>
-    constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+    [[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
         return {-x, -y, -z};
     }
 
-    constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
+    [[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
         return {x * other.x, y * other.y, z * other.z};
     }
 
     template <typename V>
-    constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
+    [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
         return {x * f, y * f, z * f};
     }
 
@@ -246,7 +246,7 @@ public:
         return *this;
     }
     template <typename V>
-    constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
+    [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
         return {x / f, y / f, z / f};
     }
 
@@ -256,20 +256,20 @@ public:
         return *this;
     }
 
-    constexpr T Length2() const {
+    [[nodiscard]] constexpr T Length2() const {
         return x * x + y * y + z * z;
     }
 
     // Only implemented for T=float
-    float Length() const;
-    Vec3 Normalized() const;
-    float Normalize(); // returns the previous length, which is often useful
+    [[nodiscard]] float Length() const;
+    [[nodiscard]] Vec3 Normalized() const;
+    [[nodiscard]] float Normalize(); // returns the previous length, which is often useful
 
-    constexpr T& operator[](std::size_t i) {
+    [[nodiscard]] constexpr T& operator[](std::size_t i) {
         return *((&x) + i);
     }
 
-    constexpr const T& operator[](std::size_t i) const {
+    [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
         return *((&x) + i);
     }
 
@@ -280,63 +280,63 @@ public:
     }
 
     // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
-    constexpr T& u() {
+    [[nodiscard]] constexpr T& u() {
         return x;
     }
-    constexpr T& v() {
+    [[nodiscard]] constexpr T& v() {
         return y;
     }
-    constexpr T& w() {
+    [[nodiscard]] constexpr T& w() {
         return z;
     }
 
-    constexpr T& r() {
+    [[nodiscard]] constexpr T& r() {
         return x;
     }
-    constexpr T& g() {
+    [[nodiscard]] constexpr T& g() {
         return y;
     }
-    constexpr T& b() {
+    [[nodiscard]] constexpr T& b() {
         return z;
     }
 
-    constexpr T& s() {
+    [[nodiscard]] constexpr T& s() {
         return x;
     }
-    constexpr T& t() {
+    [[nodiscard]] constexpr T& t() {
         return y;
     }
-    constexpr T& q() {
+    [[nodiscard]] constexpr T& q() {
         return z;
     }
 
-    constexpr const T& u() const {
+    [[nodiscard]] constexpr const T& u() const {
         return x;
     }
-    constexpr const T& v() const {
+    [[nodiscard]] constexpr const T& v() const {
         return y;
     }
-    constexpr const T& w() const {
+    [[nodiscard]] constexpr const T& w() const {
         return z;
     }
 
-    constexpr const T& r() const {
+    [[nodiscard]] constexpr const T& r() const {
         return x;
     }
-    constexpr const T& g() const {
+    [[nodiscard]] constexpr const T& g() const {
         return y;
     }
-    constexpr const T& b() const {
+    [[nodiscard]] constexpr const T& b() const {
         return z;
     }
 
-    constexpr const T& s() const {
+    [[nodiscard]] constexpr const T& s() const {
         return x;
     }
-    constexpr const T& t() const {
+    [[nodiscard]] constexpr const T& t() const {
         return y;
     }
-    constexpr const T& q() const {
+    [[nodiscard]] constexpr const T& q() const {
         return z;
     }
 
@@ -345,7 +345,7 @@ public:
 // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
 // component names (x<->r) and permutations (xy<->yx)
 #define _DEFINE_SWIZZLER2(a, b, name)                                                              \
-    constexpr Vec2<T> name() const {                                                               \
+    [[nodiscard]] constexpr Vec2<T> name() const {                                                 \
         return Vec2<T>(a, b);                                                                      \
     }
 #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4)                                             \
@@ -366,7 +366,7 @@ public:
 };
 
 template <typename T, typename V>
-constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
+[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
     return Vec3<T>(f * vec.x, f * vec.y, f * vec.z);
 }
 
@@ -402,16 +402,16 @@ public:
         : x(x_), y(y_), z(z_), w(w_) {}
 
     template <typename T2>
-    constexpr Vec4<T2> Cast() const {
+    [[nodiscard]] constexpr Vec4<T2> Cast() const {
         return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
                         static_cast<T2>(w));
     }
 
-    static constexpr Vec4 AssignToAll(const T& f) {
+    [[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) {
         return Vec4(f, f, f, f);
     }
 
-    constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
+    [[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
         return {x + other.x, y + other.y, z + other.z, w + other.w};
     }
 
@@ -423,7 +423,7 @@ public:
         return *this;
     }
 
-    constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
+    [[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
         return {x - other.x, y - other.y, z - other.z, w - other.w};
     }
 
@@ -436,16 +436,16 @@ public:
     }
 
     template <typename U = T>
-    constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
+    [[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
         return {-x, -y, -z, -w};
     }
 
-    constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
+    [[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
         return {x * other.x, y * other.y, z * other.z, w * other.w};
     }
 
     template <typename V>
-    constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
+    [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
         return {x * f, y * f, z * f, w * f};
     }
 
@@ -456,7 +456,7 @@ public:
     }
 
     template <typename V>
-    constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
+    [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
         return {x / f, y / f, z / f, w / f};
     }
 
@@ -466,15 +466,15 @@ public:
         return *this;
     }
 
-    constexpr T Length2() const {
+    [[nodiscard]] constexpr T Length2() const {
         return x * x + y * y + z * z + w * w;
     }
 
-    constexpr T& operator[](std::size_t i) {
+    [[nodiscard]] constexpr T& operator[](std::size_t i) {
         return *((&x) + i);
     }
 
-    constexpr const T& operator[](std::size_t i) const {
+    [[nodiscard]] constexpr const T& operator[](std::size_t i) const {
         return *((&x) + i);
     }
 
@@ -486,29 +486,29 @@ public:
     }
 
     // Common alias: RGBA (colors)
-    constexpr T& r() {
+    [[nodiscard]] constexpr T& r() {
         return x;
     }
-    constexpr T& g() {
+    [[nodiscard]] constexpr T& g() {
         return y;
     }
-    constexpr T& b() {
+    [[nodiscard]] constexpr T& b() {
         return z;
     }
-    constexpr T& a() {
+    [[nodiscard]] constexpr T& a() {
         return w;
     }
 
-    constexpr const T& r() const {
+    [[nodiscard]] constexpr const T& r() const {
         return x;
     }
-    constexpr const T& g() const {
+    [[nodiscard]] constexpr const T& g() const {
         return y;
     }
-    constexpr const T& b() const {
+    [[nodiscard]] constexpr const T& b() const {
         return z;
     }
-    constexpr const T& a() const {
+    [[nodiscard]] constexpr const T& a() const {
         return w;
     }
 
@@ -520,7 +520,7 @@ public:
 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
 // permutations (xy<->yx)
 #define _DEFINE_SWIZZLER2(a, b, name)                                                              \
-    constexpr Vec2<T> name() const {                                                               \
+    [[nodiscard]] constexpr Vec2<T> name() const {                                                 \
         return Vec2<T>(a, b);                                                                      \
     }
 #define DEFINE_SWIZZLER2_COMP1(a, a2)                                                              \
@@ -547,7 +547,7 @@ public:
 #undef _DEFINE_SWIZZLER2
 
 #define _DEFINE_SWIZZLER3(a, b, c, name)                                                           \
-    constexpr Vec3<T> name() const {                                                               \
+    [[nodiscard]] constexpr Vec3<T> name() const {                                                 \
         return Vec3<T>(a, b, c);                                                                   \
     }
 #define DEFINE_SWIZZLER3_COMP1(a, a2)                                                              \
@@ -581,7 +581,7 @@ public:
 };
 
 template <typename T, typename V>
-constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
+[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
     return {f * vec.x, f * vec.y, f * vec.z, f * vec.w};
 }
 
@@ -593,39 +593,41 @@ constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b
 }
 
 template <typename T>
-constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
+[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
     return a.x * b.x + a.y * b.y + a.z * b.z;
 }
 
 template <typename T>
-constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
+[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
     return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
 }
 
 template <typename T>
-constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) {
+[[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a,
+                                                                    const Vec3<T>& b) {
     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};
 }
 
 // linear interpolation via float: 0.0=begin, 1.0=end
 template <typename X>
-constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
-                                                       const float t) {
+[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
+                                                                     const float t) {
     return begin * (1.f - t) + end * t;
 }
 
 // linear interpolation via int: 0=begin, base=end
 template <typename X, int base>
-constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end,
-                                                               const int t) {
+[[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin,
+                                                                             const X& end,
+                                                                             const int t) {
     return (begin * (base - t) + end * t) / base;
 }
 
 // bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
 // interpolation.
 template <typename X>
-constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s,
-                              const float t) {
+[[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11,
+                                            const float s, const float t) {
     auto y0 = Lerp(x00, x01, s);
     auto y1 = Lerp(x10, x11, s);
     return Lerp(y0, y1, t);
@@ -633,42 +635,42 @@ constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X&
 
 // Utility vector factories
 template <typename T>
-constexpr Vec2<T> MakeVec(const T& x, const T& y) {
+[[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) {
     return Vec2<T>{x, y};
 }
 
 template <typename T>
-constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
+[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
     return Vec3<T>{x, y, z};
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
     return MakeVec(x, y, zw[0], zw[1]);
 }
 
 template <typename T>
-constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
+[[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
     return MakeVec(xy[0], xy[1], z);
 }
 
 template <typename T>
-constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
+[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
     return MakeVec(x, yz[0], yz[1]);
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
     return Vec4<T>{x, y, z, w};
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
     return MakeVec(xy[0], xy[1], z, w);
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
     return MakeVec(x, yz[0], yz[1], w);
 }
 
@@ -676,17 +678,17 @@ constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
 //       Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
 //       out soon enough due to misuse of the returned structure.
 template <typename T>
-constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
     return MakeVec(xy[0], xy[1], zw[0], zw[1]);
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
     return MakeVec(xyz[0], xyz[1], xyz[2], w);
 }
 
 template <typename T>
-constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
+[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
     return MakeVec(x, yzw[0], yzw[1], yzw[2]);
 }
 
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h
index da064e59e1..125cb42f09 100644
--- a/src/common/virtual_buffer.h
+++ b/src/common/virtual_buffer.h
@@ -30,23 +30,23 @@ public:
         base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
     }
 
-    constexpr const T& operator[](std::size_t index) const {
+    [[nodiscard]] constexpr const T& operator[](std::size_t index) const {
         return base_ptr[index];
     }
 
-    constexpr T& operator[](std::size_t index) {
+    [[nodiscard]] constexpr T& operator[](std::size_t index) {
         return base_ptr[index];
     }
 
-    constexpr T* data() {
+    [[nodiscard]] constexpr T* data() {
         return base_ptr;
     }
 
-    constexpr const T* data() const {
+    [[nodiscard]] constexpr const T* data() const {
         return base_ptr;
     }
 
-    constexpr std::size_t size() const {
+    [[nodiscard]] constexpr std::size_t size() const {
         return alloc_size / sizeof(T);
     }
 
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 367d721348..5db30083d3 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -14,24 +14,24 @@ namespace Common {
 class WallClock {
 public:
     /// Returns current wall time in nanoseconds
-    virtual std::chrono::nanoseconds GetTimeNS() = 0;
+    [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
 
     /// Returns current wall time in microseconds
-    virtual std::chrono::microseconds GetTimeUS() = 0;
+    [[nodiscard]] virtual std::chrono::microseconds GetTimeUS() = 0;
 
     /// Returns current wall time in milliseconds
-    virtual std::chrono::milliseconds GetTimeMS() = 0;
+    [[nodiscard]] virtual std::chrono::milliseconds GetTimeMS() = 0;
 
     /// Returns current wall time in emulated clock cycles
-    virtual u64 GetClockCycles() = 0;
+    [[nodiscard]] virtual u64 GetClockCycles() = 0;
 
     /// Returns current wall time in emulated cpu cycles
-    virtual u64 GetCPUCycles() = 0;
+    [[nodiscard]] virtual u64 GetCPUCycles() = 0;
 
     virtual void Pause(bool is_paused) = 0;
 
     /// Tells if the wall clock, uses the host CPU's hardware clock
-    bool IsNative() const {
+    [[nodiscard]] bool IsNative() const {
         return is_native;
     }
 
@@ -47,7 +47,7 @@ private:
     bool is_native;
 };
 
-std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
-                                                   u32 emulated_clock_frequency);
+[[nodiscard]] std::unique_ptr<WallClock> CreateBestMatchingClock(u32 emulated_cpu_frequency,
+                                                                 u32 emulated_clock_frequency);
 
 } // namespace Common
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
index b5edf19e7e..4bacf8355a 100644
--- a/src/common/zstd_compression.h
+++ b/src/common/zstd_compression.h
@@ -19,7 +19,7 @@ namespace Common::Compression {
  *
  * @return the compressed data.
  */
-std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level);
+[[nodiscard]] std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_level);
 
 /**
  * Compresses a source memory region with Zstandard with the default compression level and returns
@@ -29,7 +29,7 @@ std::vector<u8> CompressDataZSTD(std::span<const u8> source, s32 compression_lev
  *
  * @return the compressed data.
  */
-std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source);
+[[nodiscard]] std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source);
 
 /**
  * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
@@ -38,6 +38,6 @@ std::vector<u8> CompressDataZSTDDefault(std::span<const u8> source);
  *
  * @return the decompressed data.
  */
-std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
+[[nodiscard]] std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
 
 } // namespace Common::Compression
\ No newline at end of file