syncpoint_manager.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // SPDX-FileCopyrightText: 2021 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. #include "common/microprofile.h"
  4. #include "video_core/host1x/syncpoint_manager.h"
  5. namespace Tegra {
  6. namespace Host1x {
  7. MICROPROFILE_DEFINE(GPU_wait, "GPU", "Wait for the GPU", MP_RGB(128, 128, 192));
  8. SyncpointManager::ActionHandle SyncpointManager::RegisterAction(
  9. std::atomic<u32>& syncpoint, std::list<RegisteredAction>& action_storage, u32 expected_value,
  10. std::function<void()>&& action) {
  11. if (syncpoint.load(std::memory_order_acquire) >= expected_value) {
  12. action();
  13. return {};
  14. }
  15. std::unique_lock lk(guard);
  16. if (syncpoint.load(std::memory_order_relaxed) >= expected_value) {
  17. action();
  18. return {};
  19. }
  20. auto it = action_storage.begin();
  21. while (it != action_storage.end()) {
  22. if (it->expected_value >= expected_value) {
  23. break;
  24. }
  25. ++it;
  26. }
  27. return action_storage.emplace(it, expected_value, std::move(action));
  28. }
  29. void SyncpointManager::DeregisterAction(std::list<RegisteredAction>& action_storage,
  30. const ActionHandle& handle) {
  31. std::unique_lock lk(guard);
  32. // We want to ensure the iterator still exists prior to erasing it
  33. // Otherwise, if an invalid iterator was passed in then it could lead to UB
  34. // It is important to avoid UB in that case since the deregister isn't called from a locked
  35. // context
  36. for (auto it = action_storage.begin(); it != action_storage.end(); it++) {
  37. if (it == handle) {
  38. action_storage.erase(it);
  39. return;
  40. }
  41. }
  42. }
  43. void SyncpointManager::DeregisterGuestAction(u32 syncpoint_id, const ActionHandle& handle) {
  44. DeregisterAction(guest_action_storage[syncpoint_id], handle);
  45. }
  46. void SyncpointManager::DeregisterHostAction(u32 syncpoint_id, const ActionHandle& handle) {
  47. DeregisterAction(host_action_storage[syncpoint_id], handle);
  48. }
  49. void SyncpointManager::IncrementGuest(u32 syncpoint_id) {
  50. Increment(syncpoints_guest[syncpoint_id], wait_guest_cv, guest_action_storage[syncpoint_id]);
  51. }
  52. void SyncpointManager::IncrementHost(u32 syncpoint_id) {
  53. Increment(syncpoints_host[syncpoint_id], wait_host_cv, host_action_storage[syncpoint_id]);
  54. }
  55. void SyncpointManager::WaitGuest(u32 syncpoint_id, u32 expected_value) {
  56. Wait(syncpoints_guest[syncpoint_id], wait_guest_cv, expected_value);
  57. }
  58. void SyncpointManager::WaitHost(u32 syncpoint_id, u32 expected_value) {
  59. MICROPROFILE_SCOPE(GPU_wait);
  60. Wait(syncpoints_host[syncpoint_id], wait_host_cv, expected_value);
  61. }
  62. void SyncpointManager::Increment(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv,
  63. std::list<RegisteredAction>& action_storage) {
  64. auto new_value{syncpoint.fetch_add(1, std::memory_order_acq_rel) + 1};
  65. std::unique_lock lk(guard);
  66. auto it = action_storage.begin();
  67. while (it != action_storage.end()) {
  68. if (it->expected_value > new_value) {
  69. break;
  70. }
  71. it->action();
  72. it = action_storage.erase(it);
  73. }
  74. wait_cv.notify_all();
  75. }
  76. void SyncpointManager::Wait(std::atomic<u32>& syncpoint, std::condition_variable& wait_cv,
  77. u32 expected_value) {
  78. const auto pred = [&]() { return syncpoint.load(std::memory_order_acquire) >= expected_value; };
  79. if (pred()) {
  80. return;
  81. }
  82. std::unique_lock lk(guard);
  83. wait_cv.wait(lk, pred);
  84. }
  85. } // namespace Host1x
  86. } // namespace Tegra