| 
									
										
										
										
											2015-05-24 06:32:32 +02:00
										 |  |  | // Copyright 2015 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2+
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-17 16:54:31 -05:00
										 |  |  | #include <mutex>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | #include "VideoCommon/AsyncRequests.h"
 | 
					
						
							| 
									
										
										
										
											2015-03-05 17:12:24 +01:00
										 |  |  | #include "VideoCommon/Fifo.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | #include "VideoCommon/RenderBase.h"
 | 
					
						
							| 
									
										
										
										
											2016-01-17 16:54:31 -05:00
										 |  |  | #include "VideoCommon/VideoBackendBase.h"
 | 
					
						
							|  |  |  | #include "VideoCommon/VideoCommon.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | AsyncRequests AsyncRequests::s_singleton; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | AsyncRequests::AsyncRequests() : m_enable(false), m_passthrough(true) | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AsyncRequests::PullEventsInternal() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::unique_lock<std::mutex> lock(m_mutex); | 
					
						
							| 
									
										
										
										
											2016-08-05 16:04:39 +02:00
										 |  |  |   m_empty.Set(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   while (!m_queue.empty()) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     Event e = m_queue.front(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // try to merge as many efb pokes as possible
 | 
					
						
							|  |  |  |     // it's a bit hacky, but some games render a complete frame in this way
 | 
					
						
							|  |  |  |     if ((e.type == Event::EFB_POKE_COLOR || e.type == Event::EFB_POKE_Z)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       m_merged_efb_pokes.clear(); | 
					
						
							|  |  |  |       Event first_event = m_queue.front(); | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |       const auto t = first_event.type == Event::EFB_POKE_COLOR ? EFBAccessType::PokeColor : | 
					
						
							|  |  |  |                                                                  EFBAccessType::PokeZ; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |       do | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         e = m_queue.front(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         EfbPokeData d; | 
					
						
							|  |  |  |         d.data = e.efb_poke.data; | 
					
						
							|  |  |  |         d.x = e.efb_poke.x; | 
					
						
							|  |  |  |         d.y = e.efb_poke.y; | 
					
						
							|  |  |  |         m_merged_efb_pokes.push_back(d); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         m_queue.pop(); | 
					
						
							|  |  |  |       } while (!m_queue.empty() && m_queue.front().type == first_event.type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       lock.unlock(); | 
					
						
							|  |  |  |       g_renderer->PokeEFB(t, m_merged_efb_pokes.data(), m_merged_efb_pokes.size()); | 
					
						
							|  |  |  |       lock.lock(); | 
					
						
							|  |  |  |       continue; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     lock.unlock(); | 
					
						
							|  |  |  |     HandleEvent(e); | 
					
						
							|  |  |  |     lock.lock(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     m_queue.pop(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (m_wake_me_up_again) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_wake_me_up_again = false; | 
					
						
							|  |  |  |     m_cond.notify_all(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AsyncRequests::PushEvent(const AsyncRequests::Event& event, bool blocking) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::unique_lock<std::mutex> lock(m_mutex); | 
					
						
							| 
									
										
										
										
											2015-01-31 12:01:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (m_passthrough) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     HandleEvent(event); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-31 12:01:01 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-05 16:04:39 +02:00
										 |  |  |   m_empty.Clear(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_wake_me_up_again |= blocking; | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   if (!m_enable) | 
					
						
							|  |  |  |     return; | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   m_queue.push(event); | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   Fifo::RunGpu(); | 
					
						
							|  |  |  |   if (blocking) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     m_cond.wait(lock, [this] { return m_queue.empty(); }); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AsyncRequests::SetEnable(bool enable) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::unique_lock<std::mutex> lock(m_mutex); | 
					
						
							|  |  |  |   m_enable = enable; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!enable) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     // flush the queue on disabling
 | 
					
						
							|  |  |  |     while (!m_queue.empty()) | 
					
						
							|  |  |  |       m_queue.pop(); | 
					
						
							|  |  |  |     if (m_wake_me_up_again) | 
					
						
							|  |  |  |       m_cond.notify_all(); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void AsyncRequests::HandleEvent(const AsyncRequests::Event& e) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   EFBRectangle rc; | 
					
						
							|  |  |  |   switch (e.type) | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   case Event::EFB_POKE_COLOR: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data}; | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |     g_renderer->PokeEFB(EFBAccessType::PokeColor, &poke, 1); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::EFB_POKE_Z: | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     EfbPokeData poke = {e.efb_poke.x, e.efb_poke.y, e.efb_poke.data}; | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |     g_renderer->PokeEFB(EFBAccessType::PokeZ, &poke, 1); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   } | 
					
						
							|  |  |  |   break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::EFB_PEEK_COLOR: | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |     *e.efb_peek.data = | 
					
						
							|  |  |  |         g_renderer->AccessEFB(EFBAccessType::PeekColor, e.efb_peek.x, e.efb_peek.y, 0); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::EFB_PEEK_Z: | 
					
						
							| 
									
										
										
										
											2017-01-23 02:51:46 -05:00
										 |  |  |     *e.efb_peek.data = g_renderer->AccessEFB(EFBAccessType::PeekZ, e.efb_peek.x, e.efb_peek.y, 0); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::SWAP_EVENT: | 
					
						
							|  |  |  |     Renderer::Swap(e.swap_event.xfbAddr, e.swap_event.fbWidth, e.swap_event.fbStride, | 
					
						
							| 
									
										
										
										
											2016-10-08 12:56:28 +02:00
										 |  |  |                    e.swap_event.fbHeight, rc, e.time); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::BBOX_READ: | 
					
						
							|  |  |  |     *e.bbox.data = g_renderer->BBoxRead(e.bbox.index); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   case Event::PERF_QUERY: | 
					
						
							|  |  |  |     g_perf_query->FlushResults(); | 
					
						
							|  |  |  |     break; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2015-01-31 11:38:23 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-01-31 12:01:01 +01:00
										 |  |  | void AsyncRequests::SetPassthrough(bool enable) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::unique_lock<std::mutex> lock(m_mutex); | 
					
						
							|  |  |  |   m_passthrough = enable; | 
					
						
							| 
									
										
										
										
											2015-01-31 12:01:01 +01:00
										 |  |  | } |