Throttle SetEvent call in render thread (#3511)

Reduce unnecessary SetEvent CPU overhead by using `std::atomic_flag` to avoid setting kernel events when the painting thread is already awake and running.
This commit is contained in:
Chester Liu
2020-02-15 05:58:28 +08:00
committed by GitHub
parent b3145e4ec8
commit 081493e5f1
2 changed files with 26 additions and 1 deletions

View File

@@ -17,6 +17,8 @@ RenderThread::RenderThread() :
_fKeepRunning(true),
_hPaintEnabledEvent(nullptr)
{
_fNextFrameRequested.clear();
_fPainting.clear();
}
RenderThread::~RenderThread()
@@ -158,10 +160,21 @@ DWORD WINAPI RenderThread::_ThreadProc()
while (_fKeepRunning)
{
WaitForSingleObject(_hPaintEnabledEvent, INFINITE);
WaitForSingleObject(_hEvent, INFINITE);
// Skip waiting if next frame is requested.
if (_fNextFrameRequested.test_and_set(std::memory_order_relaxed))
{
_fNextFrameRequested.clear(std::memory_order_relaxed);
}
else
{
WaitForSingleObject(_hEvent, INFINITE);
}
ResetEvent(_hPaintCompletedEvent);
_fPainting.test_and_set(std::memory_order_acquire);
LOG_IF_FAILED(_pRenderer->PaintFrame());
SetEvent(_hPaintCompletedEvent);
@@ -171,6 +184,8 @@ DWORD WINAPI RenderThread::_ThreadProc()
{
Sleep(s_FrameLimitMilliseconds);
}
_fPainting.clear(std::memory_order_release);
}
return S_OK;
@@ -178,6 +193,14 @@ DWORD WINAPI RenderThread::_ThreadProc()
void RenderThread::NotifyPaint()
{
// If we are currently painting a frame, set _fNextFrameRequested flag
// to indicate we want to paint next frame immediately.
if (_fPainting.test_and_set(std::memory_order_acquire))
{
_fNextFrameRequested.test_and_set(std::memory_order_relaxed);
return;
}
SetEvent(_hEvent);
}

View File

@@ -47,5 +47,7 @@ namespace Microsoft::Console::Render
IRenderer* _pRenderer; // Non-ownership pointer
bool _fKeepRunning;
std::atomic_flag _fNextFrameRequested;
std::atomic_flag _fPainting;
};
}