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 yuzu emulator early access
============= =============
This is the source code for early-access 3466. This is the source code for early-access 3467.
## Legal Notice ## Legal Notice

View File

@ -8,7 +8,6 @@
#include <cstddef> #include <cstddef>
#include <mutex> #include <mutex>
#include <new> #include <new>
#include <version>
#include "common/polyfill_thread.h" #include "common/polyfill_thread.h"
@ -23,33 +22,16 @@ class SPSCQueue {
static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two."); static_assert((Capacity & (Capacity - 1)) == 0, "Capacity must be a power of two.");
public: public:
bool TryPush(T&& t) {
return Push<PushMode::Try>(std::move(t));
}
template <typename... Args> template <typename... Args>
bool TryEmplace(Args&&... args) { bool TryEmplace(Args&&... args) {
return Emplace<PushMode::Try>(std::forward<Args>(args)...); return Emplace<PushMode::Try>(std::forward<Args>(args)...);
} }
void PushWait(T&& t) {
Push<PushMode::Wait>(std::move(t));
}
template <typename... Args> template <typename... Args>
void EmplaceWait(Args&&... args) { void EmplaceWait(Args&&... args) {
Emplace<PushMode::Wait>(std::forward<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) { bool TryPop(T& t) {
return Pop<PopMode::Try>(t); return Pop<PopMode::Try>(t);
} }
@ -74,25 +56,10 @@ public:
return t; 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: private:
enum class PushMode { enum class PushMode {
Try, Try,
Wait, Wait,
Overwrite,
Count, Count,
}; };
@ -103,68 +70,21 @@ private:
Count, 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> template <PushMode Mode, typename... Args>
bool Emplace(Args&&... 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) { if constexpr (Mode == PushMode::Try) {
// Check if we have free slots to write to. // 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; return false;
} }
} else if constexpr (Mode == PushMode::Wait) { } else if constexpr (Mode == PushMode::Wait) {
// Wait until we have free slots to write to. // Wait until we have free slots to write to.
std::unique_lock lock{producer_cv_mutex}; std::unique_lock lock{producer_cv_mutex};
producer_cv.wait(lock, [this, write_index] { 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 { } else {
static_assert(Mode < PushMode::Count, "Invalid PushMode."); static_assert(Mode < PushMode::Count, "Invalid PushMode.");
} }
@ -185,47 +105,30 @@ private:
return true; 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> template <PopMode Mode>
bool Pop(T& t, [[maybe_unused]] std::stop_token stop_token = {}) { 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) { if constexpr (Mode == PopMode::Try) {
// Check if the queue is empty. // 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; return false;
} }
} else if constexpr (Mode == PopMode::Wait) { } else if constexpr (Mode == PopMode::Wait) {
// Wait until the queue is not empty. // Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex}; std::unique_lock lock{consumer_cv_mutex};
consumer_cv.wait(lock, consumer_cv.wait(lock, [this, read_index] {
[this, read_index] { return read_index != m_write_index.load(); }); return read_index != m_write_index.load(std::memory_order::acquire);
});
} else if constexpr (Mode == PopMode::WaitWithStopToken) { } else if constexpr (Mode == PopMode::WaitWithStopToken) {
// Wait until the queue is not empty. // Wait until the queue is not empty.
std::unique_lock lock{consumer_cv_mutex}; std::unique_lock lock{consumer_cv_mutex};
Common::CondvarWait(consumer_cv, lock, stop_token, Common::CondvarWait(consumer_cv, lock, stop_token, [this, read_index] {
[this, read_index] { return read_index != m_write_index.load(); }); return read_index != m_write_index.load(std::memory_order::acquire);
});
if (stop_token.stop_requested()) {
return false;
}
} else { } else {
static_assert(Mode < PopMode::Count, "Invalid PopMode."); static_assert(Mode < PopMode::Count, "Invalid PopMode.");
} }
@ -246,13 +149,8 @@ private:
return true; return true;
} }
#ifdef __cpp_lib_hardware_interference_size alignas(128) std::atomic_size_t m_read_index{0};
alignas(std::hardware_destructive_interference_size) std::atomic_size_t m_read_index{0}; alignas(128) std::atomic_size_t m_write_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
std::array<T, Capacity> m_data; std::array<T, Capacity> m_data;
@ -265,39 +163,18 @@ private:
template <typename T, size_t Capacity = detail::DefaultCapacity> template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPSCQueue { class MPSCQueue {
public: public:
bool TryPush(T&& t) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryPush(std::move(t));
}
template <typename... Args> template <typename... Args>
bool TryEmplace(Args&&... args) { bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex}; std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...); 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> template <typename... Args>
void EmplaceWait(Args&&... args) { void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex}; std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...); 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) { bool TryPop(T& t) {
return spsc_queue.TryPop(t); return spsc_queue.TryPop(t);
} }
@ -318,18 +195,6 @@ public:
return spsc_queue.PopWait(stop_token); 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: private:
SPSCQueue<T, Capacity> spsc_queue; SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex; std::mutex write_mutex;
@ -338,39 +203,18 @@ private:
template <typename T, size_t Capacity = detail::DefaultCapacity> template <typename T, size_t Capacity = detail::DefaultCapacity>
class MPMCQueue { class MPMCQueue {
public: public:
bool TryPush(T&& t) {
std::scoped_lock lock{write_mutex};
return spsc_queue.TryPush(std::move(t));
}
template <typename... Args> template <typename... Args>
bool TryEmplace(Args&&... args) { bool TryEmplace(Args&&... args) {
std::scoped_lock lock{write_mutex}; std::scoped_lock lock{write_mutex};
return spsc_queue.TryEmplace(std::forward<Args>(args)...); 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> template <typename... Args>
void EmplaceWait(Args&&... args) { void EmplaceWait(Args&&... args) {
std::scoped_lock lock{write_mutex}; std::scoped_lock lock{write_mutex};
spsc_queue.EmplaceWait(std::forward<Args>(args)...); 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) { bool TryPop(T& t) {
std::scoped_lock lock{read_mutex}; std::scoped_lock lock{read_mutex};
return spsc_queue.TryPop(t); return spsc_queue.TryPop(t);
@ -396,21 +240,6 @@ public:
return spsc_queue.PopWait(stop_token); 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: private:
SPSCQueue<T, Capacity> spsc_queue; SPSCQueue<T, Capacity> spsc_queue;
std::mutex write_mutex; 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(); state.cv.notify_all();
} }
} }
// Drain the queue.
state.queue.Clear();
} }
ThreadManager::ThreadManager(Core::System& system_, bool is_async_) ThreadManager::ThreadManager(Core::System& system_, bool is_async_)