yuzu/src/video_core/host1x/syncpoint_manager.cpp
Lioncash c4af7b3f5c host1x/syncpoint_manager: Pass DeregisterAction() handle as const-ref
The handle is only compared against and not modified in any way, so we
can pass it by const reference.

This also allows us to mark the respective parameters for
DeregisterGuestAction() and DeregisterHostAction() as const references
as well.
2022-11-29 08:55:33 -05:00

107 lines
3.5 KiB
C++

// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/microprofile.h"
#include "video_core/host1x/syncpoint_manager.h"
namespace Tegra {
namespace Host1x {
MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
SyncpointManager::ActionHandle SyncpointManager::RegisterAction(
std::atomic<u32>& syncpoint, std::list<RegisteredAction>& action_storage, u32 expected_value,
std::function<void()>&& action) {
if (syncpoint.load(std::memory_order_acquire) >= expected_value) {
action();
return {};
}
std::unique_lock 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, std::move(action));
}
void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_storage,
const ActionHandle& handle) {
std::unique_lock lk(guard);
// We want to ensure the iterator still exists prior to erasing it
// Otherwise, if an invalid iterator was passed in then it could lead to UB
// It is important to avoid UB in that case since the deregister isn't called from a locked
// context
for (auto it = action_storage.begin(); it != action_storage.end(); it++) {
if (it == handle) {
action_storage.erase(it);
return;
}
}
}
void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle) {
DeregisterAction(guest_action_storage[syncpoint_id], handle);
}
void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, const 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) {
MICROPROFILE_SCOPE(GPU_wait);
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 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 lk(guard);
wait_cv.wait(lk, pred);
}
} // namespace Host1x
} // namespace Tegra