mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-15 21:19:47 +00:00
3f52bf4b4b
This insufferable work tries to cover some holes on previous threading implementation from yuzu's team, starting with Windows and Linux reordering of priorities (NICE), reworks previous Android's threading and cpu affinity with adpf, adjust emulated clocks/gpu for better "accuracy" with their work, bumps android minSDK for all flavors, legacy will now work with AP 29 to cover A10 - A12, standard will reach A13 as base and finally the optimized build will come with API 35, mostly targeted on devices with A15 support and newer, NDK and AGP wasn't upgraded yet. The performance cost efficiency have been improved based on device power configuration; preventing overheating if certain devices tended to fall into NICE0 (not allocated threads priority, all task ran with higher priority, 11 tasks running within the limited 2 - 7 threads available on the most common configuration 1x3x4 or 1x4x3). Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4254
119 lines
2.9 KiB
C++
119 lines
2.9 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
|
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <atomic>
|
|
#include <chrono>
|
|
#include <condition_variable>
|
|
#include <cstddef>
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include "common/common_types.h"
|
|
#include "common/polyfill_thread.h"
|
|
|
|
namespace Common {
|
|
|
|
class Event {
|
|
public:
|
|
void Set() {
|
|
std::scoped_lock lk{mutex};
|
|
if (!is_set) {
|
|
is_set = true;
|
|
condvar.notify_one();
|
|
}
|
|
}
|
|
|
|
void Wait() {
|
|
std::unique_lock lk{mutex};
|
|
condvar.wait(lk, [&] { return is_set.load(); });
|
|
is_set = false;
|
|
}
|
|
|
|
bool WaitFor(const std::chrono::nanoseconds time);
|
|
|
|
template<class Clock, class Duration>
|
|
bool WaitUntil(const std::chrono::time_point<Clock, Duration> time) {
|
|
std::unique_lock lk{mutex};
|
|
if (!condvar.wait_until(lk, time, [this] { return is_set.load(); }))
|
|
return false;
|
|
is_set = false;
|
|
return true;
|
|
}
|
|
|
|
void Reset() {
|
|
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;
|
|
}
|
|
|
|
[[nodiscard]] bool IsSet() const {
|
|
return is_set;
|
|
}
|
|
|
|
private:
|
|
alignas(64) std::atomic<bool> is_set{false};
|
|
std::condition_variable condvar;
|
|
std::mutex mutex;
|
|
};
|
|
|
|
class Barrier {
|
|
public:
|
|
explicit Barrier(std::size_t count_) : count(count_) {}
|
|
|
|
/// Blocks until all "count" threads have called Sync()
|
|
bool Sync(std::stop_token token = {}) {
|
|
std::unique_lock lk{mutex};
|
|
const std::size_t current_generation = generation;
|
|
|
|
if (++waiting == count) {
|
|
generation++;
|
|
waiting = 0;
|
|
condvar.notify_all();
|
|
return true;
|
|
} else {
|
|
condvar.wait(lk, token,
|
|
[this, current_generation] { return current_generation != generation; });
|
|
return !token.stop_requested();
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::condition_variable_any condvar;
|
|
std::mutex mutex;
|
|
std::size_t count;
|
|
std::size_t waiting = 0;
|
|
std::size_t generation = 0; // Incremented once each time the barrier is used
|
|
};
|
|
|
|
enum class ThreadPriority : u32 {
|
|
Low = 0,
|
|
Normal = 1,
|
|
High = 2,
|
|
VeryHigh = 3,
|
|
Critical = 4,
|
|
};
|
|
|
|
enum class ThreadPlacement : u32 {
|
|
Default = 0,
|
|
Background = 1,
|
|
Efficiency = 2,
|
|
};
|
|
|
|
void SetCurrentThreadPriority(ThreadPriority new_priority);
|
|
void SetCurrentThreadName(const char* name);
|
|
void SetCurrentThreadToPerformanceCores();
|
|
void SetCurrentThreadToEfficiencyCores();
|
|
void SetCurrentThreadToBackgroundWork();
|
|
void SetCurrentThreadToAllCores();
|
|
|
|
void RefreshThreadPolicies();
|
|
void PollThreadPolicies();
|
|
|
|
} // namespace Common
|