mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
VBlank: If previous frame is still in progress, wait until next frame to trigger a new vblank
Previously, the vblank's thread loop would block on each iteration until the current async callback had finished, at which point a new async callback would be immediately triggered. The new implementation only waits on the vblank event. If a vblank callback is still in progress the next time the vblank event is signalled, we assume the last frame is overrunning and avoid sending a new async update. The intention of this change is to avoid saturating the message thread with expensive vblank callbacks. It's also nice to remove a lock, although that's just an incidental change.
This commit is contained in:
parent
f887979ec0
commit
d3d7d4c89c
1 changed files with 19 additions and 34 deletions
|
|
@ -56,12 +56,7 @@ public:
|
|||
{
|
||||
cancelPendingUpdate();
|
||||
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
threadState = ThreadState::exit;
|
||||
}
|
||||
|
||||
condvar.notify_one();
|
||||
state |= flagExit;
|
||||
|
||||
stopThread (-1);
|
||||
}
|
||||
|
|
@ -121,24 +116,24 @@ private:
|
|||
{
|
||||
if (output->WaitForVBlank() == S_OK)
|
||||
{
|
||||
if (const auto now = Time::getMillisecondCounterHiRes();
|
||||
now - lastVBlankEvent.exchange (now) < 1.0)
|
||||
{
|
||||
Thread::sleep (1);
|
||||
}
|
||||
const auto now = Time::getMillisecondCounterHiRes();
|
||||
|
||||
std::unique_lock lock { mutex };
|
||||
condvar.wait (lock, [this] { return threadState != ThreadState::sleep; });
|
||||
if (now - lastVBlankEvent.exchange (now) < 1.0)
|
||||
sleep (1);
|
||||
|
||||
if (threadState == ThreadState::exit)
|
||||
const auto stateToRead = state.fetch_or (flagPaintPending);
|
||||
|
||||
if ((stateToRead & flagExit) != 0)
|
||||
return;
|
||||
|
||||
threadState = ThreadState::sleep;
|
||||
if ((stateToRead & flagPaintPending) != 0)
|
||||
continue;
|
||||
|
||||
triggerAsyncUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
Thread::sleep (1);
|
||||
sleep (1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -150,32 +145,22 @@ private:
|
|||
for (auto& listener : listeners)
|
||||
listener.get().onVBlank (timestampSec);
|
||||
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
if (threadState == ThreadState::sleep)
|
||||
threadState = ThreadState::paint;
|
||||
}
|
||||
|
||||
condvar.notify_one();
|
||||
state &= ~flagPaintPending;
|
||||
}
|
||||
|
||||
enum Flags
|
||||
{
|
||||
flagExit = 1 << 0,
|
||||
flagPaintPending = 1 << 1,
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
ComSmartPtr<IDXGIOutput> output;
|
||||
HMONITOR monitor = nullptr;
|
||||
std::vector<std::reference_wrapper<VBlankListener>> listeners;
|
||||
|
||||
enum class ThreadState
|
||||
{
|
||||
sleep,
|
||||
paint,
|
||||
exit,
|
||||
};
|
||||
|
||||
std::atomic<double> lastVBlankEvent{};
|
||||
ThreadState threadState = ThreadState::paint;
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
std::atomic<int> state{};
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VBlankThread)
|
||||
JUCE_DECLARE_NON_MOVEABLE (VBlankThread)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue