AsyncRequests.cpp 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // Copyright 2015 Dolphin Emulator Project
  2. // Licensed under GPLv2+
  3. // Refer to the license.txt file included.
  4. #include "VideoCommon/AsyncRequests.h"
  5. #include "VideoCommon/Fifo.h"
  6. #include "VideoCommon/RenderBase.h"
  7. AsyncRequests AsyncRequests::s_singleton;
  8. AsyncRequests::AsyncRequests()
  9. : m_enable(false), m_passthrough(true)
  10. {
  11. }
  12. void AsyncRequests::PullEventsInternal()
  13. {
  14. std::unique_lock<std::mutex> lock(m_mutex);
  15. m_empty.store(true);
  16. while (!m_queue.empty())
  17. {
  18. Event e = m_queue.front();
  19. // try to merge as many efb pokes as possible
  20. // it's a bit hacky, but some games render a complete frame in this way
  21. if ((e.type == Event::EFB_POKE_COLOR || e.type == Event::EFB_POKE_Z))
  22. {
  23. m_merged_efb_pokes.clear();
  24. Event first_event = m_queue.front();
  25. EFBAccessType t = first_event.type == Event::EFB_POKE_COLOR ? POKE_COLOR : POKE_Z;
  26. do
  27. {
  28. e = m_queue.front();
  29. EfbPokeData d;
  30. d.data = e.efb_poke.data;
  31. d.x = e.efb_poke.x;
  32. d.y = e.efb_poke.y;
  33. m_merged_efb_pokes.push_back(d);
  34. m_queue.pop();
  35. } while(!m_queue.empty() && m_queue.front().type == first_event.type);
  36. lock.unlock();
  37. g_renderer->PokeEFB(t, m_merged_efb_pokes);
  38. lock.lock();
  39. continue;
  40. }
  41. lock.unlock();
  42. HandleEvent(e);
  43. lock.lock();
  44. m_queue.pop();
  45. }
  46. if (m_wake_me_up_again)
  47. {
  48. m_wake_me_up_again = false;
  49. m_cond.notify_all();
  50. }
  51. }
  52. void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking)
  53. {
  54. std::unique_lock<std::mutex> lock(m_mutex);
  55. if (m_passthrough)
  56. {
  57. HandleEvent(event);
  58. return;
  59. }
  60. m_empty.store(false);
  61. m_wake_me_up_again |= blocking;
  62. if (!m_enable)
  63. return;
  64. m_queue.push(event);
  65. RunGpu();
  66. if (blocking)
  67. {
  68. m_cond.wait(lock, [this]{return m_queue.empty();});
  69. }
  70. }
  71. void AsyncRequests::SetEnable(bool enable)
  72. {
  73. std::unique_lock<std::mutex> lock(m_mutex);
  74. m_enable = enable;
  75. if (!enable)
  76. {
  77. // flush the queue on disabling
  78. while (!m_queue.empty())
  79. m_queue.pop();
  80. if (m_wake_me_up_again)
  81. m_cond.notify_all();
  82. }
  83. }
  84. void AsyncRequests::HandleEvent(const AsyncRequests::Event& e)
  85. {
  86. EFBRectangle rc;
  87. switch (e.type)
  88. {
  89. case Event::EFB_POKE_COLOR:
  90. g_renderer->AccessEFB(POKE_COLOR, e.efb_poke.x, e.efb_poke.y, e.efb_poke.data);
  91. break;
  92. case Event::EFB_POKE_Z:
  93. g_renderer->AccessEFB(POKE_Z, e.efb_poke.x, e.efb_poke.y, e.efb_poke.data);
  94. break;
  95. case Event::EFB_PEEK_COLOR:
  96. *e.efb_peek.data = g_renderer->AccessEFB(PEEK_COLOR, e.efb_peek.x, e.efb_peek.y, 0);
  97. break;
  98. case Event::EFB_PEEK_Z:
  99. *e.efb_peek.data = g_renderer->AccessEFB(PEEK_Z, e.efb_peek.x, e.efb_peek.y, 0);
  100. break;
  101. case Event::SWAP_EVENT:
  102. Renderer::Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, e.swap_event.fbHeight, rc);
  103. break;
  104. case Event::BBOX_READ:
  105. *e.bbox.data = g_renderer->BBoxRead(e.bbox.index);
  106. break;
  107. case Event::PERF_QUERY:
  108. g_perf_query->FlushResults();
  109. break;
  110. }
  111. }
  112. void AsyncRequests::SetPassthrough(bool enable)
  113. {
  114. std::unique_lock<std::mutex> lock(m_mutex);
  115. m_passthrough = enable;
  116. }