diff options
Diffstat (limited to 'src/common')
| -rw-r--r-- | src/common/CMakeLists.txt | 5 | ||||
| -rw-r--r-- | src/common/assert.h | 18 | ||||
| -rw-r--r-- | src/common/bit_util.h | 16 | ||||
| -rw-r--r-- | src/common/lz4_compression.cpp | 76 | ||||
| -rw-r--r-- | src/common/lz4_compression.h | 57 | ||||
| -rw-r--r-- | src/common/multi_level_queue.h | 2 | ||||
| -rw-r--r-- | src/common/scope_exit.h | 2 | ||||
| -rw-r--r-- | src/common/swap.h | 96 | ||||
| -rw-r--r-- | src/common/zstd_compression.cpp | 53 | ||||
| -rw-r--r-- | src/common/zstd_compression.h | 44 |
10 files changed, 290 insertions, 79 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 850ce8006..1e8e1b215 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -91,6 +91,8 @@ add_library(common STATIC | |||
| 91 | logging/log.h | 91 | logging/log.h |
| 92 | logging/text_formatter.cpp | 92 | logging/text_formatter.cpp |
| 93 | logging/text_formatter.h | 93 | logging/text_formatter.h |
| 94 | lz4_compression.cpp | ||
| 95 | lz4_compression.h | ||
| 94 | math_util.h | 96 | math_util.h |
| 95 | memory_hook.cpp | 97 | memory_hook.cpp |
| 96 | memory_hook.h | 98 | memory_hook.h |
| @@ -123,6 +125,8 @@ add_library(common STATIC | |||
| 123 | uint128.h | 125 | uint128.h |
| 124 | vector_math.h | 126 | vector_math.h |
| 125 | web_result.h | 127 | web_result.h |
| 128 | zstd_compression.cpp | ||
| 129 | zstd_compression.h | ||
| 126 | ) | 130 | ) |
| 127 | 131 | ||
| 128 | if(ARCHITECTURE_x86_64) | 132 | if(ARCHITECTURE_x86_64) |
| @@ -136,3 +140,4 @@ endif() | |||
| 136 | create_target_directory_groups(common) | 140 | create_target_directory_groups(common) |
| 137 | 141 | ||
| 138 | target_link_libraries(common PUBLIC Boost::boost fmt microprofile) | 142 | target_link_libraries(common PUBLIC Boost::boost fmt microprofile) |
| 143 | target_link_libraries(common PRIVATE lz4_static libzstd_static) | ||
diff --git a/src/common/assert.h b/src/common/assert.h index 6002f7ab1..4b0e3f64e 100644 --- a/src/common/assert.h +++ b/src/common/assert.h | |||
| @@ -57,3 +57,21 @@ __declspec(noinline, noreturn) | |||
| 57 | 57 | ||
| 58 | #define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!") | 58 | #define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!") |
| 59 | #define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__) | 59 | #define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__) |
| 60 | |||
| 61 | // If the assert is ignored, execute _b_ | ||
| 62 | #define ASSERT_OR_EXECUTE(_a_, _b_) \ | ||
| 63 | do { \ | ||
| 64 | ASSERT(_a_); \ | ||
| 65 | if (!(_a_)) { \ | ||
| 66 | _b_ \ | ||
| 67 | } \ | ||
| 68 | } while (0) | ||
| 69 | |||
| 70 | // If the assert is ignored, execute _b_ | ||
| 71 | #define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \ | ||
| 72 | do { \ | ||
| 73 | ASSERT_MSG(_a_, __VA_ARGS__); \ | ||
| 74 | if (!(_a_)) { \ | ||
| 75 | _b_ \ | ||
| 76 | } \ | ||
| 77 | } while (0) | ||
diff --git a/src/common/bit_util.h b/src/common/bit_util.h index a4f9ed4aa..d032df413 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h | |||
| @@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) { | |||
| 32 | return 32; | 32 | return 32; |
| 33 | } | 33 | } |
| 34 | 34 | ||
| 35 | inline u64 CountLeadingZeroes64(u64 value) { | 35 | 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) { |
| @@ -47,15 +47,15 @@ inline u32 CountLeadingZeroes32(u32 value) { | |||
| 47 | return 32; | 47 | return 32; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | return __builtin_clz(value); | 50 | return static_cast<u32>(__builtin_clz(value)); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | inline u64 CountLeadingZeroes64(u64 value) { | 53 | inline u32 CountLeadingZeroes64(u64 value) { |
| 54 | if (value == 0) { | 54 | if (value == 0) { |
| 55 | return 64; | 55 | return 64; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | return __builtin_clzll(value); | 58 | return static_cast<u32>(__builtin_clzll(value)); |
| 59 | } | 59 | } |
| 60 | #endif | 60 | #endif |
| 61 | 61 | ||
| @@ -70,7 +70,7 @@ inline u32 CountTrailingZeroes32(u32 value) { | |||
| 70 | return 32; | 70 | return 32; |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | inline u64 CountTrailingZeroes64(u64 value) { | 73 | 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) { |
| @@ -85,15 +85,15 @@ inline u32 CountTrailingZeroes32(u32 value) { | |||
| 85 | return 32; | 85 | return 32; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| 88 | return __builtin_ctz(value); | 88 | return static_cast<u32>(__builtin_ctz(value)); |
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | inline u64 CountTrailingZeroes64(u64 value) { | 91 | inline u32 CountTrailingZeroes64(u64 value) { |
| 92 | if (value == 0) { | 92 | if (value == 0) { |
| 93 | return 64; | 93 | return 64; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | return __builtin_ctzll(value); | 96 | return static_cast<u32>(__builtin_ctzll(value)); |
| 97 | } | 97 | } |
| 98 | #endif | 98 | #endif |
| 99 | 99 | ||
diff --git a/src/common/lz4_compression.cpp b/src/common/lz4_compression.cpp new file mode 100644 index 000000000..ade6759bb --- /dev/null +++ b/src/common/lz4_compression.cpp | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <algorithm> | ||
| 6 | #include <lz4hc.h> | ||
| 7 | |||
| 8 | #include "common/assert.h" | ||
| 9 | #include "common/lz4_compression.h" | ||
| 10 | |||
| 11 | namespace Common::Compression { | ||
| 12 | |||
| 13 | 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"); | ||
| 15 | |||
| 16 | const auto source_size_int = static_cast<int>(source_size); | ||
| 17 | const int max_compressed_size = LZ4_compressBound(source_size_int); | ||
| 18 | std::vector<u8> compressed(max_compressed_size); | ||
| 19 | |||
| 20 | const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source), | ||
| 21 | reinterpret_cast<char*>(compressed.data()), | ||
| 22 | source_size_int, max_compressed_size); | ||
| 23 | |||
| 24 | if (compressed_size <= 0) { | ||
| 25 | // Compression failed | ||
| 26 | return {}; | ||
| 27 | } | ||
| 28 | |||
| 29 | compressed.resize(compressed_size); | ||
| 30 | |||
| 31 | return compressed; | ||
| 32 | } | ||
| 33 | |||
| 34 | std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, | ||
| 35 | s32 compression_level) { | ||
| 36 | ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size"); | ||
| 37 | |||
| 38 | compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX); | ||
| 39 | |||
| 40 | const auto source_size_int = static_cast<int>(source_size); | ||
| 41 | const int max_compressed_size = LZ4_compressBound(source_size_int); | ||
| 42 | std::vector<u8> compressed(max_compressed_size); | ||
| 43 | |||
| 44 | const int compressed_size = LZ4_compress_HC( | ||
| 45 | reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()), | ||
| 46 | source_size_int, max_compressed_size, compression_level); | ||
| 47 | |||
| 48 | if (compressed_size <= 0) { | ||
| 49 | // Compression failed | ||
| 50 | return {}; | ||
| 51 | } | ||
| 52 | |||
| 53 | compressed.resize(compressed_size); | ||
| 54 | |||
| 55 | return compressed; | ||
| 56 | } | ||
| 57 | |||
| 58 | std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) { | ||
| 59 | return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX); | ||
| 60 | } | ||
| 61 | |||
| 62 | std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, | ||
| 63 | std::size_t uncompressed_size) { | ||
| 64 | std::vector<u8> uncompressed(uncompressed_size); | ||
| 65 | const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()), | ||
| 66 | reinterpret_cast<char*>(uncompressed.data()), | ||
| 67 | static_cast<int>(compressed.size()), | ||
| 68 | static_cast<int>(uncompressed.size())); | ||
| 69 | if (static_cast<int>(uncompressed_size) != size_check) { | ||
| 70 | // Decompression failed | ||
| 71 | return {}; | ||
| 72 | } | ||
| 73 | return uncompressed; | ||
| 74 | } | ||
| 75 | |||
| 76 | } // namespace Common::Compression | ||
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h new file mode 100644 index 000000000..4c16f6e03 --- /dev/null +++ b/src/common/lz4_compression.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Common::Compression { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Compresses a source memory region with LZ4 and returns the compressed data in a vector. | ||
| 15 | * | ||
| 16 | * @param source the uncompressed source memory region. | ||
| 17 | * @param source_size the size in bytes of the uncompressed source memory region. | ||
| 18 | * | ||
| 19 | * @return the compressed data. | ||
| 20 | */ | ||
| 21 | std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size); | ||
| 22 | |||
| 23 | /** | ||
| 24 | * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression | ||
| 25 | * levels result in a smaller compressed size, but require more CPU time for compression. The | ||
| 26 | * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can | ||
| 27 | * also be decompressed with the default LZ4 decompression. | ||
| 28 | * | ||
| 29 | * @param source the uncompressed source memory region. | ||
| 30 | * @param source_size the size in bytes of the uncompressed source memory region. | ||
| 31 | * @param compression_level the used compression level. Should be between 3 and 12. | ||
| 32 | * | ||
| 33 | * @return the compressed data. | ||
| 34 | */ | ||
| 35 | std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level); | ||
| 36 | |||
| 37 | /** | ||
| 38 | * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level. | ||
| 39 | * | ||
| 40 | * @param source the uncompressed source memory region. | ||
| 41 | * @param source_size the size in bytes of the uncompressed source memory region. | ||
| 42 | * | ||
| 43 | * @return the compressed data. | ||
| 44 | */ | ||
| 45 | std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size); | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector. | ||
| 49 | * | ||
| 50 | * @param compressed the compressed source memory region. | ||
| 51 | * @param uncompressed_size the size in bytes of the uncompressed data. | ||
| 52 | * | ||
| 53 | * @return the decompressed data. | ||
| 54 | */ | ||
| 55 | std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed, std::size_t uncompressed_size); | ||
| 56 | |||
| 57 | } // namespace Common::Compression \ No newline at end of file | ||
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h index 2b61b91e0..9cb448f56 100644 --- a/src/common/multi_level_queue.h +++ b/src/common/multi_level_queue.h | |||
| @@ -72,7 +72,7 @@ public: | |||
| 72 | u64 prios = mlq.used_priorities; | 72 | u64 prios = mlq.used_priorities; |
| 73 | prios &= ~((1ULL << (current_priority + 1)) - 1); | 73 | prios &= ~((1ULL << (current_priority + 1)) - 1); |
| 74 | if (prios == 0) { | 74 | if (prios == 0) { |
| 75 | current_priority = mlq.depth(); | 75 | current_priority = static_cast<u32>(mlq.depth()); |
| 76 | } else { | 76 | } else { |
| 77 | current_priority = CountTrailingZeroes64(prios); | 77 | current_priority = CountTrailingZeroes64(prios); |
| 78 | it = GetBeginItForPrio(); | 78 | it = GetBeginItForPrio(); |
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h index baf1f1c9e..1176a72b1 100644 --- a/src/common/scope_exit.h +++ b/src/common/scope_exit.h | |||
| @@ -20,7 +20,7 @@ struct ScopeExitHelper { | |||
| 20 | 20 | ||
| 21 | template <typename Func> | 21 | template <typename Func> |
| 22 | ScopeExitHelper<Func> ScopeExit(Func&& func) { | 22 | ScopeExitHelper<Func> ScopeExit(Func&& func) { |
| 23 | return ScopeExitHelper<Func>(std::move(func)); | 23 | return ScopeExitHelper<Func>(std::forward<Func>(func)); |
| 24 | } | 24 | } |
| 25 | } // namespace detail | 25 | } // namespace detail |
| 26 | 26 | ||
diff --git a/src/common/swap.h b/src/common/swap.h index b3eab1324..71932c2bb 100644 --- a/src/common/swap.h +++ b/src/common/swap.h | |||
| @@ -21,11 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | #if defined(_MSC_VER) | 22 | #if defined(_MSC_VER) |
| 23 | #include <cstdlib> | 23 | #include <cstdlib> |
| 24 | #elif defined(__linux__) | ||
| 25 | #include <byteswap.h> | ||
| 26 | #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || \ | ||
| 27 | defined(__NetBSD__) || defined(__OpenBSD__) | ||
| 28 | #include <sys/endian.h> | ||
| 29 | #endif | 24 | #endif |
| 30 | #include <cstring> | 25 | #include <cstring> |
| 31 | #include "common/common_types.h" | 26 | #include "common/common_types.h" |
| @@ -62,86 +57,49 @@ | |||
| 62 | namespace Common { | 57 | namespace Common { |
| 63 | 58 | ||
| 64 | #ifdef _MSC_VER | 59 | #ifdef _MSC_VER |
| 65 | inline u16 swap16(u16 _data) { | 60 | [[nodiscard]] inline u16 swap16(u16 data) noexcept { |
| 66 | return _byteswap_ushort(_data); | 61 | return _byteswap_ushort(data); |
| 67 | } | 62 | } |
| 68 | inline u32 swap32(u32 _data) { | 63 | [[nodiscard]] inline u32 swap32(u32 data) noexcept { |
| 69 | return _byteswap_ulong(_data); | 64 | return _byteswap_ulong(data); |
| 70 | } | 65 | } |
| 71 | inline u64 swap64(u64 _data) { | 66 | [[nodiscard]] inline u64 swap64(u64 data) noexcept { |
| 72 | return _byteswap_uint64(_data); | 67 | return _byteswap_uint64(data); |
| 73 | } | 68 | } |
| 74 | #elif defined(ARCHITECTURE_ARM) && (__ARM_ARCH >= 6) | 69 | #elif defined(__clang__) || defined(__GNUC__) |
| 75 | inline u16 swap16(u16 _data) { | 70 | #if defined(__Bitrig__) || defined(__OpenBSD__) |
| 76 | u32 data = _data; | ||
| 77 | __asm__("rev16 %0, %1\n" : "=l"(data) : "l"(data)); | ||
| 78 | return (u16)data; | ||
| 79 | } | ||
| 80 | inline u32 swap32(u32 _data) { | ||
| 81 | __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data)); | ||
| 82 | return _data; | ||
| 83 | } | ||
| 84 | inline u64 swap64(u64 _data) { | ||
| 85 | return ((u64)swap32(_data) << 32) | swap32(_data >> 32); | ||
| 86 | } | ||
| 87 | #elif __linux__ | ||
| 88 | inline u16 swap16(u16 _data) { | ||
| 89 | return bswap_16(_data); | ||
| 90 | } | ||
| 91 | inline u32 swap32(u32 _data) { | ||
| 92 | return bswap_32(_data); | ||
| 93 | } | ||
| 94 | inline u64 swap64(u64 _data) { | ||
| 95 | return bswap_64(_data); | ||
| 96 | } | ||
| 97 | #elif __APPLE__ | ||
| 98 | inline __attribute__((always_inline)) u16 swap16(u16 _data) { | ||
| 99 | return (_data >> 8) | (_data << 8); | ||
| 100 | } | ||
| 101 | inline __attribute__((always_inline)) u32 swap32(u32 _data) { | ||
| 102 | return __builtin_bswap32(_data); | ||
| 103 | } | ||
| 104 | inline __attribute__((always_inline)) u64 swap64(u64 _data) { | ||
| 105 | return __builtin_bswap64(_data); | ||
| 106 | } | ||
| 107 | #elif defined(__Bitrig__) || defined(__OpenBSD__) | ||
| 108 | // redefine swap16, swap32, swap64 as inline functions | 71 | // redefine swap16, swap32, swap64 as inline functions |
| 109 | #undef swap16 | 72 | #undef swap16 |
| 110 | #undef swap32 | 73 | #undef swap32 |
| 111 | #undef swap64 | 74 | #undef swap64 |
| 112 | inline u16 swap16(u16 _data) { | 75 | #endif |
| 113 | return __swap16(_data); | 76 | [[nodiscard]] inline u16 swap16(u16 data) noexcept { |
| 114 | } | 77 | return __builtin_bswap16(data); |
| 115 | inline u32 swap32(u32 _data) { | ||
| 116 | return __swap32(_data); | ||
| 117 | } | ||
| 118 | inline u64 swap64(u64 _data) { | ||
| 119 | return __swap64(_data); | ||
| 120 | } | ||
| 121 | #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) | ||
| 122 | inline u16 swap16(u16 _data) { | ||
| 123 | return bswap16(_data); | ||
| 124 | } | 78 | } |
| 125 | inline u32 swap32(u32 _data) { | 79 | [[nodiscard]] inline u32 swap32(u32 data) noexcept { |
| 126 | return bswap32(_data); | 80 | return __builtin_bswap32(data); |
| 127 | } | 81 | } |
| 128 | inline u64 swap64(u64 _data) { | 82 | [[nodiscard]] inline u64 swap64(u64 data) noexcept { |
| 129 | return bswap64(_data); | 83 | return __builtin_bswap64(data); |
| 130 | } | 84 | } |
| 131 | #else | 85 | #else |
| 132 | // Slow generic implementation. | 86 | // Generic implementation. |
| 133 | inline u16 swap16(u16 data) { | 87 | [[nodiscard]] inline u16 swap16(u16 data) noexcept { |
| 134 | return (data >> 8) | (data << 8); | 88 | return (data >> 8) | (data << 8); |
| 135 | } | 89 | } |
| 136 | inline u32 swap32(u32 data) { | 90 | [[nodiscard]] inline u32 swap32(u32 data) noexcept { |
| 137 | return (swap16(data) << 16) | swap16(data >> 16); | 91 | return ((data & 0xFF000000U) >> 24) | ((data & 0x00FF0000U) >> 8) | |
| 92 | ((data & 0x0000FF00U) << 8) | ((data & 0x000000FFU) << 24); | ||
| 138 | } | 93 | } |
| 139 | inline u64 swap64(u64 data) { | 94 | [[nodiscard]] inline u64 swap64(u64 data) noexcept { |
| 140 | return ((u64)swap32(data) << 32) | swap32(data >> 32); | 95 | return ((data & 0xFF00000000000000ULL) >> 56) | ((data & 0x00FF000000000000ULL) >> 40) | |
| 96 | ((data & 0x0000FF0000000000ULL) >> 24) | ((data & 0x000000FF00000000ULL) >> 8) | | ||
| 97 | ((data & 0x00000000FF000000ULL) << 8) | ((data & 0x0000000000FF0000ULL) << 24) | | ||
| 98 | ((data & 0x000000000000FF00ULL) << 40) | ((data & 0x00000000000000FFULL) << 56); | ||
| 141 | } | 99 | } |
| 142 | #endif | 100 | #endif |
| 143 | 101 | ||
| 144 | inline float swapf(float f) { | 102 | [[nodiscard]] inline float swapf(float f) noexcept { |
| 145 | static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t."); | 103 | static_assert(sizeof(u32) == sizeof(float), "float must be the same size as uint32_t."); |
| 146 | 104 | ||
| 147 | u32 value; | 105 | u32 value; |
| @@ -153,7 +111,7 @@ inline float swapf(float f) { | |||
| 153 | return f; | 111 | return f; |
| 154 | } | 112 | } |
| 155 | 113 | ||
| 156 | inline double swapd(double f) { | 114 | [[nodiscard]] inline double swapd(double f) noexcept { |
| 157 | static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t."); | 115 | static_assert(sizeof(u64) == sizeof(double), "double must be the same size as uint64_t."); |
| 158 | 116 | ||
| 159 | u64 value; | 117 | u64 value; |
diff --git a/src/common/zstd_compression.cpp b/src/common/zstd_compression.cpp new file mode 100644 index 000000000..60a35c67c --- /dev/null +++ b/src/common/zstd_compression.cpp | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <zstd.h> | ||
| 9 | |||
| 10 | #include "common/assert.h" | ||
| 11 | #include "common/zstd_compression.h" | ||
| 12 | |||
| 13 | namespace Common::Compression { | ||
| 14 | |||
| 15 | std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) { | ||
| 16 | compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel()); | ||
| 17 | |||
| 18 | const std::size_t max_compressed_size = ZSTD_compressBound(source_size); | ||
| 19 | std::vector<u8> compressed(max_compressed_size); | ||
| 20 | |||
| 21 | const std::size_t compressed_size = | ||
| 22 | ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level); | ||
| 23 | |||
| 24 | if (ZSTD_isError(compressed_size)) { | ||
| 25 | // Compression failed | ||
| 26 | return {}; | ||
| 27 | } | ||
| 28 | |||
| 29 | compressed.resize(compressed_size); | ||
| 30 | |||
| 31 | return compressed; | ||
| 32 | } | ||
| 33 | |||
| 34 | std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) { | ||
| 35 | return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT); | ||
| 36 | } | ||
| 37 | |||
| 38 | std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) { | ||
| 39 | const std::size_t decompressed_size = | ||
| 40 | ZSTD_getDecompressedSize(compressed.data(), compressed.size()); | ||
| 41 | std::vector<u8> decompressed(decompressed_size); | ||
| 42 | |||
| 43 | const std::size_t uncompressed_result_size = ZSTD_decompress( | ||
| 44 | decompressed.data(), decompressed.size(), compressed.data(), compressed.size()); | ||
| 45 | |||
| 46 | if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) { | ||
| 47 | // Decompression failed | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | return decompressed; | ||
| 51 | } | ||
| 52 | |||
| 53 | } // namespace Common::Compression | ||
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h new file mode 100644 index 000000000..e9de941c8 --- /dev/null +++ b/src/common/zstd_compression.h | |||
| @@ -0,0 +1,44 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | |||
| 11 | namespace Common::Compression { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Compresses a source memory region with Zstandard and returns the compressed data in a vector. | ||
| 15 | * | ||
| 16 | * @param source the uncompressed source memory region. | ||
| 17 | * @param source_size the size in bytes of the uncompressed source memory region. | ||
| 18 | * @param compression_level the used compression level. Should be between 1 and 22. | ||
| 19 | * | ||
| 20 | * @return the compressed data. | ||
| 21 | */ | ||
| 22 | std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level); | ||
| 23 | |||
| 24 | /** | ||
| 25 | * Compresses a source memory region with Zstandard with the default compression level and returns | ||
| 26 | * the compressed data in a vector. | ||
| 27 | * | ||
| 28 | * @param source the uncompressed source memory region. | ||
| 29 | * @param source_size the size in bytes of the uncompressed source memory region. | ||
| 30 | * | ||
| 31 | * @return the compressed data. | ||
| 32 | */ | ||
| 33 | std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size); | ||
| 34 | |||
| 35 | /** | ||
| 36 | * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector. | ||
| 37 | * | ||
| 38 | * @param compressed the compressed source memory region. | ||
| 39 | * | ||
| 40 | * @return the decompressed data. | ||
| 41 | */ | ||
| 42 | std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed); | ||
| 43 | |||
| 44 | } // namespace Common::Compression \ No newline at end of file | ||