mirror of https://github.com/PCSX2/pcsx2.git
MTGS: Support 'running idle', i.e. redisplaying the current frame
This commit is contained in:
parent
be3f120548
commit
d466184a02
|
@ -26,6 +26,30 @@
|
||||||
// Semaphore Implementations
|
// Semaphore Implementations
|
||||||
// --------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool Threading::WorkSema::CheckForWork()
|
||||||
|
{
|
||||||
|
s32 value = m_state.load(std::memory_order_relaxed);
|
||||||
|
pxAssert(!IsDead(value));
|
||||||
|
|
||||||
|
// we want to switch to the running state, but preserve the waiting empty bit for RUNNING_N -> RUNNING_0
|
||||||
|
// otherwise, we clear the waiting flag (since we're notifying the waiter that we're empty below)
|
||||||
|
while (!m_state.compare_exchange_weak(value,
|
||||||
|
IsReadyForSleep(value) ? STATE_RUNNING_0 : (value & STATE_FLAG_WAITING_EMPTY),
|
||||||
|
std::memory_order_acq_rel, std::memory_order_relaxed))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're not empty, we have work to do
|
||||||
|
if (!IsReadyForSleep(value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// this means we're empty, so notify any waiters
|
||||||
|
if (value & STATE_FLAG_WAITING_EMPTY)
|
||||||
|
m_empty_sema.Post();
|
||||||
|
|
||||||
|
// no work to do
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void Threading::WorkSema::WaitForWork()
|
void Threading::WorkSema::WaitForWork()
|
||||||
{
|
{
|
||||||
|
|
|
@ -211,6 +211,8 @@ namespace Threading
|
||||||
m_sema.Post();
|
m_sema.Post();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if there's any work in the queue
|
||||||
|
bool CheckForWork();
|
||||||
/// Wait for work to be added to the queue
|
/// Wait for work to be added to the queue
|
||||||
void WaitForWork();
|
void WaitForWork();
|
||||||
/// Wait for work to be added to the queue, spinning for a bit before sleeping the thread
|
/// Wait for work to be added to the queue, spinning for a bit before sleeping the thread
|
||||||
|
|
|
@ -367,6 +367,7 @@ public:
|
||||||
Threading::ThreadHandle m_thread_handle;
|
Threading::ThreadHandle m_thread_handle;
|
||||||
std::atomic_bool m_open_flag{false};
|
std::atomic_bool m_open_flag{false};
|
||||||
std::atomic_bool m_shutdown_flag{false};
|
std::atomic_bool m_shutdown_flag{false};
|
||||||
|
std::atomic_bool m_run_idle_flag{false};
|
||||||
Threading::KernelSemaphore m_open_or_close_done;
|
Threading::KernelSemaphore m_open_or_close_done;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -416,6 +417,7 @@ public:
|
||||||
void SetSoftwareRendering(bool software, bool display_message = true);
|
void SetSoftwareRendering(bool software, bool display_message = true);
|
||||||
void ToggleSoftwareRendering();
|
void ToggleSoftwareRendering();
|
||||||
bool SaveMemorySnapshot(u32 width, u32 height, std::vector<u32>* pixels);
|
bool SaveMemorySnapshot(u32 width, u32 height, std::vector<u32>* pixels);
|
||||||
|
void SetRunIdle(bool enabled);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool TryOpenGS();
|
bool TryOpenGS();
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#ifndef PCSX2_CORE
|
#ifndef PCSX2_CORE
|
||||||
#include "gui/Dialogs/ModalPopups.h"
|
#include "gui/Dialogs/ModalPopups.h"
|
||||||
|
#else
|
||||||
|
#include "VMManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Uncomment this to enable profiling of the GS RingBufferCopy function.
|
// Uncomment this to enable profiling of the GS RingBufferCopy function.
|
||||||
|
@ -296,9 +298,23 @@ void SysMtgsThread::MainLoop()
|
||||||
// is very optimized (only 1 instruction test in most cases), so no point in trying
|
// is very optimized (only 1 instruction test in most cases), so no point in trying
|
||||||
// to avoid it.
|
// to avoid it.
|
||||||
|
|
||||||
|
#ifdef PCSX2_CORE
|
||||||
|
if (m_run_idle_flag.load(std::memory_order_acquire) && VMManager::GetState() != VMState::Running)
|
||||||
|
{
|
||||||
|
if (!m_sem_event.CheckForWork())
|
||||||
|
GSPresentCurrentFrame();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
mtvu_lock.unlock();
|
mtvu_lock.unlock();
|
||||||
m_sem_event.WaitForWork();
|
m_sem_event.WaitForWork();
|
||||||
mtvu_lock.lock();
|
mtvu_lock.lock();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
mtvu_lock.unlock();
|
||||||
|
m_sem_event.WaitForWork();
|
||||||
|
mtvu_lock.lock();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!m_open_flag.load(std::memory_order_acquire))
|
if (!m_open_flag.load(std::memory_order_acquire))
|
||||||
break;
|
break;
|
||||||
|
@ -1005,3 +1021,9 @@ void SysMtgsThread::PresentCurrentFrame()
|
||||||
{
|
{
|
||||||
GSPresentCurrentFrame();
|
GSPresentCurrentFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SysMtgsThread::SetRunIdle(bool enabled)
|
||||||
|
{
|
||||||
|
// NOTE: Should only be called on the GS thread.
|
||||||
|
m_run_idle_flag.store(enabled, std::memory_order_release);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue