94 lines
3 KiB
C++
94 lines
3 KiB
C++
|
// Copyright 2021 yuzu Emulator Project
|
||
|
// Licensed under GPLv3 or any later version
|
||
|
// Refer to the license.txt file included.
|
||
|
|
||
|
#include "video_core/host1x/syncpoint_manager.h"
|
||
|
|
||
|
namespace Tegra {
|
||
|
|
||
|
namespace Host1x {
|
||
|
|
||
|
SyncpointManager::ActionHandle SyncpointManager::RegisterAction(
|
||
|
std::atomic<u32>& syncpoint, std::list<RegisteredAction>& action_storage, u32 expected_value,
|
||
|
std::function<void(void)>& action) {
|
||
|
if (syncpoint.load(std::memory_order_acquire) >= expected_value) {
|
||
|
action();
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
std::unique_lock<std::mutex> lk(guard);
|
||
|
if (syncpoint.load(std::memory_order_relaxed) >= expected_value) {
|
||
|
action();
|
||
|
return {};
|
||
|
}
|
||
|
auto it = action_storage.begin();
|
||
|
while (it != action_storage.end()) {
|
||
|
if (it->expected_value >= expected_value) {
|
||
|
break;
|
||
|
}
|
||
|
++it;
|
||
|
}
|
||
|
return action_storage.emplace(it, expected_value, action);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_storage,
|
||
|
ActionHandle& handle) {
|
||
|
std::unique_lock<std::mutex> lk(guard);
|
||
|
action_storage.erase(handle);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, ActionHandle& handle) {
|
||
|
DeregisterAction(guest_action_storage[syncpoint_id], handle);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, ActionHandle& handle) {
|
||
|
DeregisterAction(host_action_storage[syncpoint_id], handle);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::IncrementGuest(u32 syncpoint_id) {
|
||
|
Increment(syncpoints_guest[syncpoint_id], wait_guest_cv, guest_action_storage[syncpoint_id]);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::IncrementHost(u32 syncpoint_id) {
|
||
|
Increment(syncpoints_host[syncpoint_id], wait_host_cv, host_action_storage[syncpoint_id]);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::WaitGuest(u32 syncpoint_id, u32 expected_value) {
|
||
|
Wait(syncpoints_guest[syncpoint_id], wait_guest_cv, expected_value);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::WaitHost(u32 syncpoint_id, u32 expected_value) {
|
||
|
Wait(syncpoints_host[syncpoint_id], wait_host_cv, expected_value);
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::Increment(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv,
|
||
|
std::list<RegisteredAction>& action_storage) {
|
||
|
auto new_value{syncpoint.fetch_add(1, std::memory_order_acq_rel) + 1};
|
||
|
|
||
|
std::unique_lock<std::mutex> lk(guard);
|
||
|
auto it = action_storage.begin();
|
||
|
while (it != action_storage.end()) {
|
||
|
if (it->expected_value > new_value) {
|
||
|
break;
|
||
|
}
|
||
|
it->action();
|
||
|
it = action_storage.erase(it);
|
||
|
}
|
||
|
wait_cv.notify_all();
|
||
|
}
|
||
|
|
||
|
void SyncpointManager::Wait(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv,
|
||
|
u32 expected_value) {
|
||
|
const auto pred = [&]() { return syncpoint.load(std::memory_order_acquire) >= expected_value; };
|
||
|
if (pred()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
std::unique_lock<std::mutex> lk(guard);
|
||
|
wait_cv.wait(lk, pred);
|
||
|
}
|
||
|
|
||
|
} // namespace Host1x
|
||
|
|
||
|
} // namespace Tegra
|