summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt5
-rw-r--r--src/common/assert.h18
-rw-r--r--src/common/bit_util.h16
-rw-r--r--src/common/lz4_compression.cpp76
-rw-r--r--src/common/lz4_compression.h57
-rw-r--r--src/common/multi_level_queue.h2
-rw-r--r--src/common/scope_exit.h2
-rw-r--r--src/common/swap.h96
-rw-r--r--src/common/zstd_compression.cpp53
-rw-r--r--src/common/zstd_compression.h44
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
128if(ARCHITECTURE_x86_64) 132if(ARCHITECTURE_x86_64)
@@ -136,3 +140,4 @@ endif()
136create_target_directory_groups(common) 140create_target_directory_groups(common)
137 141
138target_link_libraries(common PUBLIC Boost::boost fmt microprofile) 142target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
143target_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
35inline u64 CountLeadingZeroes64(u64 value) { 35inline 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
53inline u64 CountLeadingZeroes64(u64 value) { 53inline 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
73inline u64 CountTrailingZeroes64(u64 value) { 73inline 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
91inline u64 CountTrailingZeroes64(u64 value) { 91inline 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
11namespace Common::Compression {
12
13std::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
34std::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
58std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) {
59 return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX);
60}
61
62std::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
11namespace 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 */
21std::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 */
35std::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 */
45std::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 */
55std::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
21template <typename Func> 21template <typename Func>
22ScopeExitHelper<Func> ScopeExit(Func&& func) { 22ScopeExitHelper<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 @@
62namespace Common { 57namespace Common {
63 58
64#ifdef _MSC_VER 59#ifdef _MSC_VER
65inline u16 swap16(u16 _data) { 60[[nodiscard]] inline u16 swap16(u16 data) noexcept {
66 return _byteswap_ushort(_data); 61 return _byteswap_ushort(data);
67} 62}
68inline u32 swap32(u32 _data) { 63[[nodiscard]] inline u32 swap32(u32 data) noexcept {
69 return _byteswap_ulong(_data); 64 return _byteswap_ulong(data);
70} 65}
71inline 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__)
75inline 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}
80inline u32 swap32(u32 _data) {
81 __asm__("rev %0, %1\n" : "=l"(_data) : "l"(_data));
82 return _data;
83}
84inline u64 swap64(u64 _data) {
85 return ((u64)swap32(_data) << 32) | swap32(_data >> 32);
86}
87#elif __linux__
88inline u16 swap16(u16 _data) {
89 return bswap_16(_data);
90}
91inline u32 swap32(u32 _data) {
92 return bswap_32(_data);
93}
94inline u64 swap64(u64 _data) {
95 return bswap_64(_data);
96}
97#elif __APPLE__
98inline __attribute__((always_inline)) u16 swap16(u16 _data) {
99 return (_data >> 8) | (_data << 8);
100}
101inline __attribute__((always_inline)) u32 swap32(u32 _data) {
102 return __builtin_bswap32(_data);
103}
104inline __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
112inline u16 swap16(u16 _data) { 75#endif
113 return __swap16(_data); 76[[nodiscard]] inline u16 swap16(u16 data) noexcept {
114} 77 return __builtin_bswap16(data);
115inline u32 swap32(u32 _data) {
116 return __swap32(_data);
117}
118inline u64 swap64(u64 _data) {
119 return __swap64(_data);
120}
121#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__)
122inline u16 swap16(u16 _data) {
123 return bswap16(_data);
124} 78}
125inline u32 swap32(u32 _data) { 79[[nodiscard]] inline u32 swap32(u32 data) noexcept {
126 return bswap32(_data); 80 return __builtin_bswap32(data);
127} 81}
128inline 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.
133inline 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}
136inline 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}
139inline 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
144inline 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
156inline 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
13namespace Common::Compression {
14
15std::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
34std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
35 return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
36}
37
38std::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
11namespace 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 */
22std::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 */
33std::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 */
42std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
43
44} // namespace Common::Compression \ No newline at end of file