AsyncRequests.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. // Copyright 2015 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "VideoCommon/AsyncRequests.h"
  4. #include <mutex>
  5. #include "Core/System.h"
  6. #include "VideoCommon/BoundingBox.h"
  7. #include "VideoCommon/Fifo.h"
  8. #include "VideoCommon/Present.h"
  9. #include "VideoCommon/RenderBase.h"
  10. #include "VideoCommon/Statistics.h"
  11. #include "VideoCommon/VertexManagerBase.h"
  12. #include "VideoCommon/VideoBackendBase.h"
  13. #include "VideoCommon/VideoCommon.h"
  14. #include "VideoCommon/VideoEvents.h"
  15. #include "VideoCommon/VideoState.h"
  16. AsyncRequests AsyncRequests::s_singleton;
  17. AsyncRequests::AsyncRequests() = default;
  18. void AsyncRequests::PullEventsInternal()
  19. {
  20. // This is only called if the queue isn't empty.
  21. // So just flush the pipeline to get accurate results.
  22. g_vertex_manager->Flush();
  23. std::unique_lock<std::mutex> lock(m_mutex);
  24. m_empty.Set();
  25. while (!m_queue.empty())
  26. {
  27. Event e = m_queue.front();
  28. // try to merge as many efb pokes as possible
  29. // it's a bit hacky, but some games render a complete frame in this way
  30. if ((e.type == Event::EFB_POKE_COLOR || e.type == Event::EFB_POKE_Z))
  31. {
  32. m_merged_efb_pokes.clear();
  33. Event first_event = m_queue.front();
  34. const auto t = first_event.type == Event::EFB_POKE_COLOR ? EFBAccessType::PokeColor :
  35. EFBAccessType::PokeZ;
  36. do
  37. {
  38. e = m_queue.front();
  39. EfbPokeData d;
  40. d.data = e.efb_poke.data;
  41. d.x = e.efb_poke.x;
  42. d.y = e.efb_poke.y;
  43. m_merged_efb_pokes.push_back(d);
  44. m_queue.pop();
  45. } while (!m_queue.empty() && m_queue.front().type == first_event.type);
  46. lock.unlock();
  47. g_renderer->PokeEFB(t, m_merged_efb_pokes.data(), m_merged_efb_pokes.size());
  48. lock.lock();
  49. continue;
  50. }
  51. lock.unlock();
  52. HandleEvent(e);
  53. lock.lock();
  54. m_queue.pop();
  55. }
  56. if (m_wake_me_up_again)
  57. {
  58. m_wake_me_up_again = false;
  59. m_cond.notify_all();
  60. }
  61. }
  62. void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking)
  63. {
  64. std::unique_lock<std::mutex> lock(m_mutex);
  65. if (m_passthrough)
  66. {
  67. HandleEvent(event);
  68. return;
  69. }
  70. m_empty.Clear();
  71. m_wake_me_up_again |= blocking;
  72. if (!m_enable)
  73. return;
  74. m_queue.push(event);
  75. auto& system = Core::System::GetInstance();
  76. system.GetFifo().RunGpu();
  77. if (blocking)
  78. {
  79. m_cond.wait(lock, [this] { return m_queue.empty(); });
  80. }
  81. }
  82. void AsyncRequests::WaitForEmptyQueue()
  83. {
  84. std::unique_lock<std::mutex> lock(m_mutex);
  85. m_cond.wait(lock, [this] { return m_queue.empty(); });
  86. }
  87. void AsyncRequests::SetEnable(bool enable)
  88. {
  89. std::unique_lock<std::mutex> lock(m_mutex);
  90. m_enable = enable;
  91. if (!enable)
  92. {
  93. // flush the queue on disabling
  94. while (!m_queue.empty())
  95. m_queue.pop();
  96. if (m_wake_me_up_again)
  97. m_cond.notify_all();
  98. }
  99. }
  100. void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
  101. {
  102. switch (e.type)
  103. {
  104. case Event::EFB_POKE_COLOR:
  105. {
  106. INCSTAT(g_stats.this_frame.num_efb_pokes);
  107. EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data};
  108. g_renderer->PokeEFB(EFBAccessType::PokeColor, &poke, 1);
  109. }
  110. break;
  111. case Event::EFB_POKE_Z:
  112. {
  113. INCSTAT(g_stats.this_frame.num_efb_pokes);
  114. EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data};
  115. g_renderer->PokeEFB(EFBAccessType::PokeZ, &poke, 1);
  116. }
  117. break;
  118. case Event::EFB_PEEK_COLOR:
  119. INCSTAT(g_stats.this_frame.num_efb_peeks);
  120. *e.efb_peek.data =
  121. g_renderer->AccessEFB(EFBAccessType::PeekColor, e.efb_peek.x, e.efb_peek.y, 0);
  122. break;
  123. case Event::EFB_PEEK_Z:
  124. INCSTAT(g_stats.this_frame.num_efb_peeks);
  125. *e.efb_peek.data = g_renderer->AccessEFB(EFBAccessType::PeekZ, e.efb_peek.x, e.efb_peek.y, 0);
  126. break;
  127. case Event::SWAP_EVENT:
  128. g_presenter->ViSwap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride,
  129. e.swap_event.fbHeight, e.time);
  130. break;
  131. case Event::BBOX_READ:
  132. *e.bbox.data = g_bounding_box->Get(e.bbox.index);
  133. break;
  134. case Event::FIFO_RESET:
  135. Core::System::GetInstance().GetFifo().ResetVideoBuffer();
  136. break;
  137. case Event::PERF_QUERY:
  138. g_perf_query->FlushResults();
  139. break;
  140. case Event::DO_SAVE_STATE:
  141. VideoCommon_DoState(*e.do_save_state.p);
  142. break;
  143. }
  144. }
  145. void AsyncRequests::SetPassthrough(bool enable)
  146. {
  147. std::unique_lock<std::mutex> lock(m_mutex);
  148. m_passthrough = enable;
  149. }