early-access version 3467

This commit is contained in:
pineappleEA 2023-03-20 08:00:30 +01:00
parent 6cdaf33559
commit b560fc14bf
3 changed files with 17 additions and 191 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access
=============
This is the source code for early-access 3466.
This is the source code for early-access 3467.
## Legal Notice

View file

@ -8,7 +8,6 @@
#include <cstddef>
#include <mutex>
#include <new>
#include <version>
#include "common/polyfill_thread.h"
@ -23,33 +22,16 @@ class SPSCQueue {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
public:
bool TryPush(T&& t) {
return Push<PushMode::Try>(std::move(t));
}
template <typename... Args>
bool TryEmplace(Args&&... args) {
return Emplace<PushMode::Try>(std::forward<Args>(args)...);
}
void PushWait(T&& t) {
Push<PushMode::Wait>(std::move(t));
}
template <typename... Args>
void EmplaceWait(Args&&... args) {
Emplace<PushMode::Wait>(std::forward<Args>(args)...);
}
void PushOverwrite(T&& t) {
Push<PushMode::Overwrite>(std::move(t));
}
template <typename... Args>
void EmplaceOverwrite(Args&&... args) {
Emplace<PushMode::Overwrite>(std::forward<Args>(args)...);
}
bool TryPop(T& t) {
return Pop<PopMode::Try>(t);
}
@ -74,25 +56,10 @@ public:
return t;
}
void Clear() {
while (!Empty()) {
Pop();
}
}
bool Empty() const {
return m_read_index.load() == m_write_index.load();
}
size_t Size() const {
return m_write_index.load() - m_read_index.load();
}
private:
enum class PushMode {
Try,
Wait,
Overwrite,
Count,
};
@ -103,68 +70,21 @@ private:
Count,
};
template <PushMode Mode>
bool Push(T&& t) {
const size_t write_index = m_write_index.load();
if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load()) == Capacity) {
return false;
}
} else if constexpr (Mode == PushMode::Wait) {
// Wait until we have free slots to write to.
std::unique_lock lock{producer_cv_mutex};
producer_cv.wait(lock, [this, write_index] {
return (write_index - m_read_index.load()) < Capacity;
});
} else if constexpr (Mode == PushMode::Overwrite) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load()) == Capacity) {
// If we don't, increment the read index. This is effectively a pop operation.
++m_read_index;
}
} else {
static_assert(Mode < PushMode::Count, "Invalid PushMode.");
}
// Determine the position to write to.
const size_t pos = write_index % Capacity;
// Push into the queue.
m_data[pos] = std::move(t);
// Increment the write index.
++m_write_index;
// Notify the consumer that we have pushed into the queue.
std::scoped_lock lock{consumer_cv_mutex};
consumer_cv.notify_one();
return true;
}
template <PushMode Mode, typename... Args>
bool Emplace(Args&&... args) {
const size_t write_index = m_write_index.load();
const size_t write_index = m_write_index.load(std::memory_order::relaxed);
if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load()) == Capacity) {
if ((write_index - m_read_index.load(std::memory_order::acquire)) == Capacity) {
return false;
}
} else if constexpr (Mode == PushMode::Wait) {
// Wait until we have free slots to write to.
std::unique_lock lock{producer_cv_mutex};
producer_cv.wait(lock, [this, write_index] {
return (write_index - m_read_index.load()) < Capacity;
return (write_index - m_read_index.load(std::memory_order::acquire)) < Capacity;
});
} else if constexpr (Mode == PushMode::Overwrite) {
// Check if we have free slots to write to.
if ((write_index - m_read_index.load()) == Capacity) {
// If we don't, increment the read index. This is effectively a pop operation.
++m_read_index;
}
} else {
static_assert(Mode < PushMode::Count, "Invalid PushMode.");
}
@ -185,47 +105,30 @@ private:
return true;
}
void Pop() {
const size_t read_index = m_read_index.load();
// Check if the queue is empty.
if (read_index == m_write_index.load()) {
return;
}
// Determine the position to read from.
const size_t pos = read_index % Capacity;
// Pop the data off the queue, deleting it.
std::destroy_at(std::addressof(m_data[pos]));
// Increment the read index.
++m_read_index;
// Notify the producer that we have popped off the queue.
std::unique_lock lock{producer_cv_mutex};
producer_cv.notify_one();
}
template <PopMode Mode>
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) {
const size_t read_index = m_read_index.load();
const size_t read_index = m_read_index.load(std::memory_order::relaxed);
if constexpr (Mode == PopMode::Try) {
// Check if the queue is empty.
if (read_index == m_write_index.load()) {
if (read_index == m_write_index.load(std::memory_order::acquire)) {
return false;
}
} else if constexpr (Mode == PopMode::Wait) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
consumer_cv.wait(lock,
[this, read_index] { return read_index != m_write_index.load(); });
consumer_cv.wait(lock, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
} else if constexpr (Mode == PopMode::WaitWithStopToken) {
// Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex};
Common::CondvarWait(consumer_cv, lock, stop_token,
[this, read_index] { return read_index != m_write_index.load(); });
Common::CondvarWait(consumer_cv, lock, stop_token, [this, read_index] {
return read_index != m_write_index.load(std::memory_order::acquire);
});
if (stop_token.stop_requested()) {
return false;
}
} else {
static_assert(Mode < PopMode::Count, "Invalid PopMode.");
}
@ -246,13 +149,8 @@ private:
return true;
}
#ifdef __cpp_lib_hardware_interference_size
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0};
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_write_index{0};
#else
alignas(64) std::atomic_size_t m_read_index{0};
alignas(64) std::atomic_size_t m_write_index{0};
#endif
alignas(128) std::atomic_size_t m_read_index{0};
alignas(128) std::atomic_size_t m_write_index{0};
std::array<T, Capacity> m_data;
@ -265,39 +163,18 @@ private:
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPSCQueue {
public:
bool TryPush(T&& t) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryPush(std::move(t));
}
template <typename... Args>
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
void PushWait(T&& t) {
std::scoped_lock lock{write_mutex};
spsc_queue.PushWait(std::move(t));
}
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
void PushOverwrite(T&& t) {
std::scoped_lock lock{write_mutex};
spsc_queue.PushOverwrite(std::move(t));
}
template <typename... Args>
void EmplaceOverwrite(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceOverwrite(std::forward<Args>(args)...);
}
bool TryPop(T& t) {
return spsc_queue.TryPop(t);
}
@ -318,18 +195,6 @@ public:
return spsc_queue.PopWait(stop_token);
}
void Clear() {
spsc_queue.Clear();
}
bool Empty() {
return spsc_queue.Empty();
}
size_t Size() {
return spsc_queue.Size();
}
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;
@ -338,39 +203,18 @@ private:
template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPMCQueue {
public:
bool TryPush(T&& t) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryPush(std::move(t));
}
template <typename... Args>
bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...);
}
void PushWait(T&& t) {
std::scoped_lock lock{write_mutex};
spsc_queue.PushWait(std::move(t));
}
template <typename... Args>
void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...);
}
void PushOverwrite(T&& t) {
std::scoped_lock lock{write_mutex};
spsc_queue.PushOverwrite(std::move(t));
}
template <typename... Args>
void EmplaceOverwrite(Args&&... args) {
std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceOverwrite(std::forward<Args>(args)...);
}
bool TryPop(T& t) {
std::scoped_lock lock{read_mutex};
return spsc_queue.TryPop(t);
@ -396,21 +240,6 @@ public:
return spsc_queue.PopWait(stop_token);
}
void Clear() {
std::scoped_lock lock{read_mutex};
spsc_queue.Clear();
}
bool Empty() {
std::scoped_lock lock{read_mutex};
return spsc_queue.Empty();
}
size_t Size() {
std::scoped_lock lock{read_mutex};
return spsc_queue.Size();
}
private:
SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex;

View file

@ -59,9 +59,6 @@ static void RunThread(std::stop_token stop_token, Core::System& system,
state.cv.notify_all();
}
}
// Drain the queue.
state.queue.Clear();
}
ThreadManager::ThreadManager(Core::System& system_, bool is_async_)