summaryrefslogtreecommitdiffstats
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt6
-rw-r--r--src/common/assert.h18
-rw-r--r--src/common/bit_util.h47
-rw-r--r--src/common/detached_tasks.cpp8
-rw-r--r--src/common/logging/backend.cpp6
-rw-r--r--src/common/lz4_compression.cpp76
-rw-r--r--src/common/lz4_compression.h55
-rw-r--r--src/common/multi_level_queue.h337
-rw-r--r--src/common/thread.cpp37
-rw-r--r--src/common/thread.h14
-rw-r--r--src/common/threadsafe_queue.h4
-rw-r--r--src/common/zstd_compression.cpp53
-rw-r--r--src/common/zstd_compression.h42
13 files changed, 644 insertions, 59 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 43ae8a9e7..1e8e1b215 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -91,6 +91,8 @@ add_library(common STATIC
logging/log.h
logging/text_formatter.cpp
logging/text_formatter.h
+ lz4_compression.cpp
+ lz4_compression.h
math_util.h
memory_hook.cpp
memory_hook.h
@@ -98,6 +100,7 @@ add_library(common STATIC
microprofile.h
microprofileui.h
misc.cpp
+ multi_level_queue.h
page_table.cpp
page_table.h
param_package.cpp
@@ -122,6 +125,8 @@ add_library(common STATIC
uint128.h
vector_math.h
web_result.h
+ zstd_compression.cpp
+ zstd_compression.h
)
if(ARCHITECTURE_x86_64)
@@ -135,3 +140,4 @@ endif()
create_target_directory_groups(common)
target_link_libraries(common PUBLIC Boost::boost fmt microprofile)
+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)
#define UNIMPLEMENTED_IF(cond) ASSERT_MSG(!(cond), "Unimplemented code!")
#define UNIMPLEMENTED_IF_MSG(cond, ...) ASSERT_MSG(!(cond), __VA_ARGS__)
+
+// If the assert is ignored, execute _b_
+#define ASSERT_OR_EXECUTE(_a_, _b_) \
+ do { \
+ ASSERT(_a_); \
+ if (!(_a_)) { \
+ _b_ \
+ } \
+ } while (0)
+
+// If the assert is ignored, execute _b_
+#define ASSERT_OR_EXECUTE_MSG(_a_, _b_, ...) \
+ do { \
+ ASSERT_MSG(_a_, __VA_ARGS__); \
+ if (!(_a_)) { \
+ _b_ \
+ } \
+ } while (0)
diff --git a/src/common/bit_util.h b/src/common/bit_util.h
index 1eea17ba1..d032df413 100644
--- a/src/common/bit_util.h
+++ b/src/common/bit_util.h
@@ -32,7 +32,7 @@ inline u32 CountLeadingZeroes32(u32 value) {
return 32;
}
-inline u64 CountLeadingZeroes64(u64 value) {
+inline u32 CountLeadingZeroes64(u64 value) {
unsigned long leading_zero = 0;
if (_BitScanReverse64(&leading_zero, value) != 0) {
@@ -47,15 +47,54 @@ inline u32 CountLeadingZeroes32(u32 value) {
return 32;
}
- return __builtin_clz(value);
+ return static_cast<u32>(__builtin_clz(value));
}
-inline u64 CountLeadingZeroes64(u64 value) {
+inline u32 CountLeadingZeroes64(u64 value) {
if (value == 0) {
return 64;
}
- return __builtin_clzll(value);
+ return static_cast<u32>(__builtin_clzll(value));
}
#endif
+
+#ifdef _MSC_VER
+inline u32 CountTrailingZeroes32(u32 value) {
+ unsigned long trailing_zero = 0;
+
+ if (_BitScanForward(&trailing_zero, value) != 0) {
+ return trailing_zero;
+ }
+
+ return 32;
+}
+
+inline u32 CountTrailingZeroes64(u64 value) {
+ unsigned long trailing_zero = 0;
+
+ if (_BitScanForward64(&trailing_zero, value) != 0) {
+ return trailing_zero;
+ }
+
+ return 64;
+}
+#else
+inline u32 CountTrailingZeroes32(u32 value) {
+ if (value == 0) {
+ return 32;
+ }
+
+ return static_cast<u32>(__builtin_ctz(value));
+}
+
+inline u32 CountTrailingZeroes64(u64 value) {
+ if (value == 0) {
+ return 64;
+ }
+
+ return static_cast<u32>(__builtin_ctzll(value));
+}
+#endif
+
} // namespace Common
diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp
index a347d9e02..f268d6021 100644
--- a/src/common/detached_tasks.cpp
+++ b/src/common/detached_tasks.cpp
@@ -16,22 +16,22 @@ DetachedTasks::DetachedTasks() {
}
void DetachedTasks::WaitForAllTasks() {
- std::unique_lock<std::mutex> lock(mutex);
+ std::unique_lock lock{mutex};
cv.wait(lock, [this]() { return count == 0; });
}
DetachedTasks::~DetachedTasks() {
- std::unique_lock<std::mutex> lock(mutex);
+ std::unique_lock lock{mutex};
ASSERT(count == 0);
instance = nullptr;
}
void DetachedTasks::AddTask(std::function<void()> task) {
- std::unique_lock<std::mutex> lock(instance->mutex);
+ std::unique_lock lock{instance->mutex};
++instance->count;
std::thread([task{std::move(task)}]() {
task();
- std::unique_lock<std::mutex> lock(instance->mutex);
+ std::unique_lock lock{instance->mutex};
--instance->count;
std::notify_all_at_thread_exit(instance->cv, std::move(lock));
})
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 4462ff3fb..a03179520 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -46,12 +46,12 @@ public:
}
void AddBackend(std::unique_ptr<Backend> backend) {
- std::lock_guard<std::mutex> lock(writing_mutex);
+ std::lock_guard lock{writing_mutex};
backends.push_back(std::move(backend));
}
void RemoveBackend(std::string_view backend_name) {
- std::lock_guard<std::mutex> lock(writing_mutex);
+ std::lock_guard lock{writing_mutex};
const auto it =
std::remove_if(backends.begin(), backends.end(),
[&backend_name](const auto& i) { return backend_name == i->GetName(); });
@@ -80,7 +80,7 @@ private:
backend_thread = std::thread([&] {
Entry entry;
auto write_logs = [&](Entry& e) {
- std::lock_guard<std::mutex> lock(writing_mutex);
+ std::lock_guard lock{writing_mutex};
for (const auto& backend : backends) {
backend->Write(e);
}
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 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <lz4hc.h>
+
+#include "common/assert.h"
+#include "common/lz4_compression.h"
+
+namespace Common::Compression {
+
+std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size) {
+ ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
+
+ const auto source_size_int = static_cast<int>(source_size);
+ const int max_compressed_size = LZ4_compressBound(source_size_int);
+ std::vector<u8> compressed(max_compressed_size);
+
+ const int compressed_size = LZ4_compress_default(reinterpret_cast<const char*>(source),
+ reinterpret_cast<char*>(compressed.data()),
+ source_size_int, max_compressed_size);
+
+ if (compressed_size <= 0) {
+ // Compression failed
+ return {};
+ }
+
+ compressed.resize(compressed_size);
+
+ return compressed;
+}
+
+std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size,
+ s32 compression_level) {
+ ASSERT_MSG(source_size <= LZ4_MAX_INPUT_SIZE, "Source size exceeds LZ4 maximum input size");
+
+ compression_level = std::clamp(compression_level, LZ4HC_CLEVEL_MIN, LZ4HC_CLEVEL_MAX);
+
+ const auto source_size_int = static_cast<int>(source_size);
+ const int max_compressed_size = LZ4_compressBound(source_size_int);
+ std::vector<u8> compressed(max_compressed_size);
+
+ const int compressed_size = LZ4_compress_HC(
+ reinterpret_cast<const char*>(source), reinterpret_cast<char*>(compressed.data()),
+ source_size_int, max_compressed_size, compression_level);
+
+ if (compressed_size <= 0) {
+ // Compression failed
+ return {};
+ }
+
+ compressed.resize(compressed_size);
+
+ return compressed;
+}
+
+std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size) {
+ return CompressDataLZ4HC(source, source_size, LZ4HC_CLEVEL_MAX);
+}
+
+std::vector<u8> DecompressDataLZ4(const std::vector<u8>& compressed,
+ std::size_t uncompressed_size) {
+ std::vector<u8> uncompressed(uncompressed_size);
+ const int size_check = LZ4_decompress_safe(reinterpret_cast<const char*>(compressed.data()),
+ reinterpret_cast<char*>(uncompressed.data()),
+ static_cast<int>(compressed.size()),
+ static_cast<int>(uncompressed.size()));
+ if (static_cast<int>(uncompressed_size) != size_check) {
+ // Decompression failed
+ return {};
+ }
+ return uncompressed;
+}
+
+} // namespace Common::Compression
diff --git a/src/common/lz4_compression.h b/src/common/lz4_compression.h
new file mode 100644
index 000000000..fe2231a6c
--- /dev/null
+++ b/src/common/lz4_compression.h
@@ -0,0 +1,55 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace Common::Compression {
+
+/**
+ * Compresses a source memory region with LZ4 and returns the compressed data in a vector.
+ *
+ * @param source the uncompressed source memory region.
+ * @param source_size the size in bytes of the uncompressed source memory region.
+ *
+ * @return the compressed data.
+ */
+std::vector<u8> CompressDataLZ4(const u8* source, std::size_t source_size);
+
+/**
+ * Utilizes the LZ4 subalgorithm LZ4HC with the specified compression level. Higher compression
+ * levels result in a smaller compressed size, but require more CPU time for compression. The
+ * compression level has almost no impact on decompression speed. Data compressed with LZ4HC can
+ * also be decompressed with the default LZ4 decompression.
+ *
+ * @param source the uncompressed source memory region.
+ * @param source_size the size in bytes of the uncompressed source memory region.
+ * @param compression_level the used compression level. Should be between 3 and 12.
+ *
+ * @return the compressed data.
+ */
+std::vector<u8> CompressDataLZ4HC(const u8* source, std::size_t source_size, s32 compression_level);
+
+/**
+ * Utilizes the LZ4 subalgorithm LZ4HC with the highest possible compression level.
+ *
+ * @param source the uncompressed source memory region.
+ * @param source_size the size in bytes of the uncompressed source memory region.
+ *
+ * @return the compressed data.
+ */
+std::vector<u8> CompressDataLZ4HCMax(const u8* source, std::size_t source_size);
+
+/**
+ * Decompresses a source memory region with LZ4 and returns the uncompressed data in a vector.
+ *
+ * @param compressed the compressed source memory region.
+ * @param uncompressed_size the size in bytes of the uncompressed data.
+ *
+ * @return the decompressed data.
+ */
+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/multi_level_queue.h b/src/common/multi_level_queue.h
new file mode 100644
index 000000000..9cb448f56
--- /dev/null
+++ b/src/common/multi_level_queue.h
@@ -0,0 +1,337 @@
+// Copyright 2019 TuxSH
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <iterator>
+#include <list>
+#include <utility>
+
+#include "common/bit_util.h"
+#include "common/common_types.h"
+
+namespace Common {
+
+/**
+ * A MultiLevelQueue is a type of priority queue which has the following characteristics:
+ * - iteratable through each of its elements.
+ * - back can be obtained.
+ * - O(1) add, lookup (both front and back)
+ * - discrete priorities and a max of 64 priorities (limited domain)
+ * This type of priority queue is normaly used for managing threads within an scheduler
+ */
+template <typename T, std::size_t Depth>
+class MultiLevelQueue {
+public:
+ using value_type = T;
+ using reference = value_type&;
+ using const_reference = const value_type&;
+ using pointer = value_type*;
+ using const_pointer = const value_type*;
+
+ using difference_type = typename std::pointer_traits<pointer>::difference_type;
+ using size_type = std::size_t;
+
+ template <bool is_constant>
+ class iterator_impl {
+ public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = T;
+ using pointer = std::conditional_t<is_constant, T*, const T*>;
+ using reference = std::conditional_t<is_constant, const T&, T&>;
+ using difference_type = typename std::pointer_traits<pointer>::difference_type;
+
+ friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) {
+ if (lhs.IsEnd() && rhs.IsEnd())
+ return true;
+ return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it);
+ }
+
+ friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) {
+ return !operator==(lhs, rhs);
+ }
+
+ reference operator*() const {
+ return *it;
+ }
+
+ pointer operator->() const {
+ return it.operator->();
+ }
+
+ iterator_impl& operator++() {
+ if (IsEnd()) {
+ return *this;
+ }
+
+ ++it;
+
+ if (it == GetEndItForPrio()) {
+ u64 prios = mlq.used_priorities;
+ prios &= ~((1ULL << (current_priority + 1)) - 1);
+ if (prios == 0) {
+ current_priority = static_cast<u32>(mlq.depth());
+ } else {
+ current_priority = CountTrailingZeroes64(prios);
+ it = GetBeginItForPrio();
+ }
+ }
+ return *this;
+ }
+
+ iterator_impl& operator--() {
+ if (IsEnd()) {
+ if (mlq.used_priorities != 0) {
+ current_priority = 63 - CountLeadingZeroes64(mlq.used_priorities);
+ it = GetEndItForPrio();
+ --it;
+ }
+ } else if (it == GetBeginItForPrio()) {
+ u64 prios = mlq.used_priorities;
+ prios &= (1ULL << current_priority) - 1;
+ if (prios != 0) {
+ current_priority = CountTrailingZeroes64(prios);
+ it = GetEndItForPrio();
+ --it;
+ }
+ } else {
+ --it;
+ }
+ return *this;
+ }
+
+ iterator_impl operator++(int) {
+ const iterator_impl v{*this};
+ ++(*this);
+ return v;
+ }
+
+ iterator_impl operator--(int) {
+ const iterator_impl v{*this};
+ --(*this);
+ return v;
+ }
+
+ // allow implicit const->non-const
+ iterator_impl(const iterator_impl<false>& other)
+ : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
+
+ iterator_impl(const iterator_impl<true>& other)
+ : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
+
+ iterator_impl& operator=(const iterator_impl<false>& other) {
+ mlq = other.mlq;
+ it = other.it;
+ current_priority = other.current_priority;
+ return *this;
+ }
+
+ friend class iterator_impl<true>;
+ iterator_impl() = default;
+
+ private:
+ friend class MultiLevelQueue;
+ using container_ref =
+ std::conditional_t<is_constant, const MultiLevelQueue&, MultiLevelQueue&>;
+ using list_iterator = std::conditional_t<is_constant, typename std::list<T>::const_iterator,
+ typename std::list<T>::iterator>;
+
+ explicit iterator_impl(container_ref mlq, list_iterator it, u32 current_priority)
+ : mlq(mlq), it(it), current_priority(current_priority) {}
+ explicit iterator_impl(container_ref mlq, u32 current_priority)
+ : mlq(mlq), it(), current_priority(current_priority) {}
+
+ bool IsEnd() const {
+ return current_priority == mlq.depth();
+ }
+
+ list_iterator GetBeginItForPrio() const {
+ return mlq.levels[current_priority].begin();
+ }
+
+ list_iterator GetEndItForPrio() const {
+ return mlq.levels[current_priority].end();
+ }
+
+ container_ref mlq;
+ list_iterator it;
+ u32 current_priority;
+ };
+
+ using iterator = iterator_impl<false>;
+ using const_iterator = iterator_impl<true>;
+
+ void add(const T& element, u32 priority, bool send_back = true) {
+ if (send_back)
+ levels[priority].push_back(element);
+ else
+ levels[priority].push_front(element);
+ used_priorities |= 1ULL << priority;
+ }
+
+ void remove(const T& element, u32 priority) {
+ auto it = ListIterateTo(levels[priority], element);
+ if (it == levels[priority].end())
+ return;
+ levels[priority].erase(it);
+ if (levels[priority].empty()) {
+ used_priorities &= ~(1ULL << priority);
+ }
+ }
+
+ void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) {
+ remove(element, old_priority);
+ add(element, new_priority, !adjust_front);
+ }
+ void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) {
+ adjust(*it, old_priority, new_priority, adjust_front);
+ }
+
+ void transfer_to_front(const T& element, u32 priority, MultiLevelQueue& other) {
+ ListSplice(other.levels[priority], other.levels[priority].begin(), levels[priority],
+ ListIterateTo(levels[priority], element));
+
+ other.used_priorities |= 1ULL << priority;
+
+ if (levels[priority].empty()) {
+ used_priorities &= ~(1ULL << priority);
+ }
+ }
+
+ void transfer_to_front(const_iterator it, u32 priority, MultiLevelQueue& other) {
+ transfer_to_front(*it, priority, other);
+ }
+
+ void transfer_to_back(const T& element, u32 priority, MultiLevelQueue& other) {
+ ListSplice(other.levels[priority], other.levels[priority].end(), levels[priority],
+ ListIterateTo(levels[priority], element));
+
+ other.used_priorities |= 1ULL << priority;
+
+ if (levels[priority].empty()) {
+ used_priorities &= ~(1ULL << priority);
+ }
+ }
+
+ void transfer_to_back(const_iterator it, u32 priority, MultiLevelQueue& other) {
+ transfer_to_back(*it, priority, other);
+ }
+
+ void yield(u32 priority, std::size_t n = 1) {
+ ListShiftForward(levels[priority], n);
+ }
+
+ std::size_t depth() const {
+ return Depth;
+ }
+
+ std::size_t size(u32 priority) const {
+ return levels[priority].size();
+ }
+
+ std::size_t size() const {
+ u64 priorities = used_priorities;
+ std::size_t size = 0;
+ while (priorities != 0) {
+ const u64 current_priority = CountTrailingZeroes64(priorities);
+ size += levels[current_priority].size();
+ priorities &= ~(1ULL << current_priority);
+ }
+ return size;
+ }
+
+ bool empty() const {
+ return used_priorities == 0;
+ }
+
+ bool empty(u32 priority) const {
+ return (used_priorities & (1ULL << priority)) == 0;
+ }
+
+ 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 {
+ 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 {
+ 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 {
+ return cbegin(max_prio);
+ }
+ 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 {
+ return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
+ }
+ const_iterator end(u32 min_prio = Depth - 1) const {
+ return cend(min_prio);
+ }
+ 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) {
+ const u32 priority = highest_priority_set(max_priority);
+ return levels[priority == Depth ? 0 : priority].front();
+ }
+ 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) {
+ 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 {
+ const u32 priority = lowest_priority_set(min_priority); // intended
+ return levels[priority == Depth ? 63 : priority].back();
+ }
+
+private:
+ using const_list_iterator = typename std::list<T>::const_iterator;
+
+ static void ListShiftForward(std::list<T>& list, const std::size_t shift = 1) {
+ if (shift >= list.size()) {
+ return;
+ }
+
+ const auto begin_range = list.begin();
+ const auto end_range = std::next(begin_range, shift);
+ list.splice(list.end(), list, begin_range, end_range);
+ }
+
+ static void ListSplice(std::list<T>& in_list, const_list_iterator position,
+ std::list<T>& out_list, const_list_iterator element) {
+ in_list.splice(position, out_list, element);
+ }
+
+ static const_list_iterator ListIterateTo(const std::list<T>& list, const T& element) {
+ auto it = list.cbegin();
+ while (it != list.cend() && *it != element) {
+ ++it;
+ }
+ return it;
+ }
+
+ std::array<std::list<T>, Depth> levels;
+ u64 used_priorities = 0;
+};
+
+} // namespace Common
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 5144c0d9f..fe7a420cc 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -27,18 +27,6 @@ namespace Common {
#ifdef _MSC_VER
-void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
- SetThreadAffinityMask(thread, mask);
-}
-
-void SetCurrentThreadAffinity(u32 mask) {
- SetThreadAffinityMask(GetCurrentThread(), mask);
-}
-
-void SwitchCurrentThread() {
- SwitchToThread();
-}
-
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
@@ -70,31 +58,6 @@ void SetCurrentThreadName(const char* name) {
#else // !MSVC_VER, so must be POSIX threads
-void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) {
-#ifdef __APPLE__
- thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1);
-#elif (defined __linux__ || defined __FreeBSD__) && !(defined ANDROID)
- cpu_set_t cpu_set;
- CPU_ZERO(&cpu_set);
-
- for (int i = 0; i != sizeof(mask) * 8; ++i)
- if ((mask >> i) & 1)
- CPU_SET(i, &cpu_set);
-
- pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set);
-#endif
-}
-
-void SetCurrentThreadAffinity(u32 mask) {
- SetThreadAffinity(pthread_self(), mask);
-}
-
-#ifndef _WIN32
-void SwitchCurrentThread() {
- usleep(1000 * 1);
-}
-#endif
-
// MinGW with the POSIX threading model does not support pthread_setname_np
#if !defined(_WIN32) || defined(_MSC_VER)
void SetCurrentThreadName(const char* name) {
diff --git a/src/common/thread.h b/src/common/thread.h
index 2cf74452d..0cfd98be6 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -9,14 +9,13 @@
#include <cstddef>
#include <mutex>
#include <thread>
-#include "common/common_types.h"
namespace Common {
class Event {
public:
void Set() {
- std::lock_guard<std::mutex> lk(mutex);
+ std::lock_guard lk{mutex};
if (!is_set) {
is_set = true;
condvar.notify_one();
@@ -24,14 +23,14 @@ public:
}
void Wait() {
- std::unique_lock<std::mutex> lk(mutex);
+ std::unique_lock lk{mutex};
condvar.wait(lk, [&] { return is_set; });
is_set = false;
}
template <class Clock, class Duration>
bool WaitUntil(const std::chrono::time_point<Clock, Duration>& time) {
- std::unique_lock<std::mutex> lk(mutex);
+ std::unique_lock lk{mutex};
if (!condvar.wait_until(lk, time, [this] { return is_set; }))
return false;
is_set = false;
@@ -39,7 +38,7 @@ public:
}
void Reset() {
- std::unique_lock<std::mutex> lk(mutex);
+ std::unique_lock lk{mutex};
// no other action required, since wait loops on the predicate and any lingering signal will
// get cleared on the first iteration
is_set = false;
@@ -57,7 +56,7 @@ public:
/// Blocks until all "count" threads have called Sync()
void Sync() {
- std::unique_lock<std::mutex> lk(mutex);
+ std::unique_lock lk{mutex};
const std::size_t current_generation = generation;
if (++waiting == count) {
@@ -78,9 +77,6 @@ private:
std::size_t generation = 0; // Incremented once each time the barrier is used
};
-void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
-void SetCurrentThreadAffinity(u32 mask);
-void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
void SetCurrentThreadName(const char* name);
} // namespace Common
diff --git a/src/common/threadsafe_queue.h b/src/common/threadsafe_queue.h
index 821e8536a..e714ba5b3 100644
--- a/src/common/threadsafe_queue.h
+++ b/src/common/threadsafe_queue.h
@@ -78,7 +78,7 @@ public:
T PopWait() {
if (Empty()) {
- std::unique_lock<std::mutex> lock(cv_mutex);
+ std::unique_lock lock{cv_mutex};
cv.wait(lock, [this]() { return !Empty(); });
}
T t;
@@ -137,7 +137,7 @@ public:
template <typename Arg>
void Push(Arg&& t) {
- std::lock_guard<std::mutex> lock(write_lock);
+ std::lock_guard lock{write_lock};
spsc_queue.Push(t);
}
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 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <algorithm>
+#include <zstd.h>
+
+#include "common/assert.h"
+#include "common/zstd_compression.h"
+
+namespace Common::Compression {
+
+std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level) {
+ compression_level = std::clamp(compression_level, 1, ZSTD_maxCLevel());
+
+ const std::size_t max_compressed_size = ZSTD_compressBound(source_size);
+ std::vector<u8> compressed(max_compressed_size);
+
+ const std::size_t compressed_size =
+ ZSTD_compress(compressed.data(), compressed.size(), source, source_size, compression_level);
+
+ if (ZSTD_isError(compressed_size)) {
+ // Compression failed
+ return {};
+ }
+
+ compressed.resize(compressed_size);
+
+ return compressed;
+}
+
+std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size) {
+ return CompressDataZSTD(source, source_size, ZSTD_CLEVEL_DEFAULT);
+}
+
+std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed) {
+ const std::size_t decompressed_size =
+ ZSTD_getDecompressedSize(compressed.data(), compressed.size());
+ std::vector<u8> decompressed(decompressed_size);
+
+ const std::size_t uncompressed_result_size = ZSTD_decompress(
+ decompressed.data(), decompressed.size(), compressed.data(), compressed.size());
+
+ if (decompressed_size != uncompressed_result_size || ZSTD_isError(uncompressed_result_size)) {
+ // Decompression failed
+ return {};
+ }
+ return decompressed;
+}
+
+} // namespace Common::Compression
diff --git a/src/common/zstd_compression.h b/src/common/zstd_compression.h
new file mode 100644
index 000000000..e0a64b035
--- /dev/null
+++ b/src/common/zstd_compression.h
@@ -0,0 +1,42 @@
+// Copyright 2019 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <vector>
+
+#include "common/common_types.h"
+
+namespace Common::Compression {
+
+/**
+ * Compresses a source memory region with Zstandard and returns the compressed data in a vector.
+ *
+ * @param source the uncompressed source memory region.
+ * @param source_size the size in bytes of the uncompressed source memory region.
+ * @param compression_level the used compression level. Should be between 1 and 22.
+ *
+ * @return the compressed data.
+ */
+std::vector<u8> CompressDataZSTD(const u8* source, std::size_t source_size, s32 compression_level);
+
+/**
+ * Compresses a source memory region with Zstandard with the default compression level and returns
+ * the compressed data in a vector.
+ *
+ * @param source the uncompressed source memory region.
+ * @param source_size the size in bytes of the uncompressed source memory region.
+ *
+ * @return the compressed data.
+ */
+std::vector<u8> CompressDataZSTDDefault(const u8* source, std::size_t source_size);
+
+/**
+ * Decompresses a source memory region with Zstandard and returns the uncompressed data in a vector.
+ *
+ * @param compressed the compressed source memory region.
+ *
+ * @return the decompressed data.
+ */
+std::vector<u8> DecompressDataZSTD(const std::vector<u8>& compressed);
+
+} // namespace Common::Compression \ No newline at end of file