mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
ComponentPeer::VBlankListener: Add timestamp parameter to the vblank callback
This commit is contained in:
parent
4bc2952419
commit
d9a3efd3cb
11 changed files with 88 additions and 33 deletions
|
|
@ -1075,9 +1075,9 @@ public:
|
|||
return areAnyWindowsInLiveResize();
|
||||
}
|
||||
|
||||
void onVBlank()
|
||||
void onVBlank (double timestampSec)
|
||||
{
|
||||
vBlankListeners.call ([] (auto& l) { l.onVBlank(); });
|
||||
callVBlankListeners (timestampSec);
|
||||
setNeedsDisplayRectangles();
|
||||
}
|
||||
|
||||
|
|
@ -1758,13 +1758,18 @@ private:
|
|||
explicit AsyncRepainter (NSViewComponentPeer& o) : owner (o) {}
|
||||
~AsyncRepainter() override { cancelPendingUpdate(); }
|
||||
|
||||
void markUpdated (const CGDirectDisplayID x)
|
||||
void markUpdated (const CGDirectDisplayID x, double timestampSec)
|
||||
{
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
||||
if (std::find (backgroundDisplays.cbegin(), backgroundDisplays.cend(), x) == backgroundDisplays.cend())
|
||||
backgroundDisplays.push_back (x);
|
||||
if (const auto it = std::find_if (backgroundVBlankEvents.cbegin(),
|
||||
backgroundVBlankEvents.cend(),
|
||||
[&x] (const auto& event) { return event.display == x; });
|
||||
it == backgroundVBlankEvents.cend())
|
||||
{
|
||||
backgroundVBlankEvents.push_back ({ x, timestampSec });
|
||||
}
|
||||
}
|
||||
|
||||
triggerAsyncUpdate();
|
||||
|
|
@ -1775,20 +1780,28 @@ private:
|
|||
{
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
mainThreadDisplays = backgroundDisplays;
|
||||
backgroundDisplays.clear();
|
||||
mainThreadVBlankEvents = backgroundVBlankEvents;
|
||||
backgroundVBlankEvents.clear();
|
||||
}
|
||||
|
||||
for (const auto& display : mainThreadDisplays)
|
||||
for (const auto& event : mainThreadVBlankEvents)
|
||||
{
|
||||
if (auto* peerView = owner.view)
|
||||
if (auto* peerWindow = [peerView window])
|
||||
if (display == ScopedDisplayLink::getDisplayIdForScreen ([peerWindow screen]))
|
||||
owner.onVBlank();
|
||||
if (event.display == ScopedDisplayLink::getDisplayIdForScreen ([peerWindow screen]))
|
||||
owner.onVBlank (event.timeSec);
|
||||
}
|
||||
}
|
||||
|
||||
struct VBlankEvent
|
||||
{
|
||||
CGDirectDisplayID display{};
|
||||
double timeSec{};
|
||||
};
|
||||
|
||||
NSViewComponentPeer& owner;
|
||||
std::mutex mutex;
|
||||
std::vector<CGDirectDisplayID> backgroundDisplays, mainThreadDisplays;
|
||||
std::vector<VBlankEvent> backgroundVBlankEvents, mainThreadVBlankEvents;
|
||||
};
|
||||
|
||||
AsyncRepainter asyncRepainter { *this };
|
||||
|
|
@ -1801,7 +1814,10 @@ private:
|
|||
{
|
||||
sharedDisplayLinks->registerFactory ([this] (CGDirectDisplayID display)
|
||||
{
|
||||
return [this, display] { asyncRepainter.markUpdated (display); };
|
||||
return [this, display] (double timestampSec)
|
||||
{
|
||||
asyncRepainter.markUpdated (display, timestampSec);
|
||||
};
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ public:
|
|||
return (CGDirectDisplayID) [[screen.deviceDescription objectForKey: @"NSScreenNumber"] unsignedIntegerValue];
|
||||
}
|
||||
|
||||
ScopedDisplayLink (NSScreen* screenIn, std::function<void()> onCallbackIn)
|
||||
ScopedDisplayLink (NSScreen* screenIn, std::function<void (double)> onCallbackIn)
|
||||
: displayId (getDisplayIdForScreen (screenIn)),
|
||||
link ([display = displayId]
|
||||
{
|
||||
|
|
@ -133,12 +133,13 @@ public:
|
|||
{
|
||||
const auto callback = [] (CVDisplayLinkRef,
|
||||
const CVTimeStamp*,
|
||||
const CVTimeStamp*,
|
||||
const CVTimeStamp* outputTime,
|
||||
CVOptionFlags,
|
||||
CVOptionFlags*,
|
||||
void* context) -> int
|
||||
{
|
||||
static_cast<const ScopedDisplayLink*> (context)->onCallback();
|
||||
const auto outputTimeSec = (double) outputTime->videoTime / (double) outputTime->videoTimeScale;
|
||||
static_cast<const ScopedDisplayLink*> (context)->onCallback (outputTimeSec);
|
||||
return kCVReturnSuccess;
|
||||
};
|
||||
|
||||
|
|
@ -179,7 +180,7 @@ private:
|
|||
|
||||
CGDirectDisplayID displayId;
|
||||
std::unique_ptr<std::remove_pointer_t<CVDisplayLinkRef>, DisplayLinkDestructor> link;
|
||||
std::function<void()> onCallback;
|
||||
std::function<void (double)> onCallback;
|
||||
|
||||
// Instances can't be copied or moved, because 'this' is passed as context to
|
||||
// CVDisplayLinkSetOutputCallback
|
||||
|
|
@ -202,7 +203,7 @@ public:
|
|||
refreshScreens();
|
||||
}
|
||||
|
||||
using RefreshCallback = std::function<void()>;
|
||||
using RefreshCallback = std::function<void (double)>;
|
||||
using Factory = std::function<RefreshCallback (CGDirectDisplayID)>;
|
||||
|
||||
/*
|
||||
|
|
@ -293,10 +294,10 @@ private:
|
|||
|
||||
// This is the callback that will actually fire in response to this screen's display
|
||||
// link callback.
|
||||
result.emplace_back (screen, [cbs = std::move (callbacks)]
|
||||
result.emplace_back (screen, [cbs = std::move (callbacks)] (double timestampSec)
|
||||
{
|
||||
for (const auto& callback : cbs)
|
||||
callback();
|
||||
callback (timestampSec);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ public:
|
|||
void setIcon (const Image& newIcon) override;
|
||||
StringArray getAvailableRenderingEngines() override { return StringArray ("CoreGraphics Renderer"); }
|
||||
|
||||
void displayLinkCallback();
|
||||
void displayLinkCallback (double timestampSec);
|
||||
|
||||
void drawRect (CGRect);
|
||||
void drawRectWithContext (CGContextRef, CGRect);
|
||||
|
|
@ -768,7 +768,7 @@ MultiTouchMapper<UITouch*> UIViewComponentPeer::currentTouches;
|
|||
- (void) displayLinkCallback: (CADisplayLink*) dl
|
||||
{
|
||||
if (owner != nullptr)
|
||||
owner->displayLinkCallback();
|
||||
owner->displayLinkCallback (dl.targetTimestamp);
|
||||
}
|
||||
|
||||
#if JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS
|
||||
|
|
@ -2160,9 +2160,9 @@ void UIViewComponentPeer::dismissPendingTextInput()
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void UIViewComponentPeer::displayLinkCallback()
|
||||
void UIViewComponentPeer::displayLinkCallback (double timestampSec)
|
||||
{
|
||||
vBlankListeners.call ([] (auto& l) { l.onVBlank(); });
|
||||
callVBlankListeners (timestampSec);
|
||||
|
||||
if (deferredRepaints.isEmpty())
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ private:
|
|||
if (output->WaitForVBlank() == S_OK)
|
||||
{
|
||||
if (const auto now = Time::getMillisecondCounterHiRes();
|
||||
now - std::exchange (lastVBlankEvent, now) < 1.0)
|
||||
now - lastVBlankEvent.exchange (now) < 1.0)
|
||||
{
|
||||
Thread::sleep (1);
|
||||
}
|
||||
|
|
@ -145,8 +145,10 @@ private:
|
|||
|
||||
void handleAsyncUpdate() override
|
||||
{
|
||||
const auto timestampSec = lastVBlankEvent / 1000.0;
|
||||
|
||||
for (auto& listener : listeners)
|
||||
listener.get().onVBlank();
|
||||
listener.get().onVBlank (timestampSec);
|
||||
|
||||
{
|
||||
const std::scoped_lock lock { mutex };
|
||||
|
|
@ -170,7 +172,7 @@ private:
|
|||
exit,
|
||||
};
|
||||
|
||||
double lastVBlankEvent = 0.0;
|
||||
std::atomic<double> lastVBlankEvent{};
|
||||
ThreadState threadState = ThreadState::paint;
|
||||
std::condition_variable condvar;
|
||||
std::mutex mutex;
|
||||
|
|
|
|||
|
|
@ -1848,7 +1848,8 @@ public:
|
|||
//==============================================================================
|
||||
static void handleDoFrameCallback (JNIEnv*, AndroidComponentPeer& t, [[maybe_unused]] int64 frameTimeNanos)
|
||||
{
|
||||
t.vBlankListeners.call ([] (auto& l) { l.onVBlank(); });
|
||||
const auto timestampSec = (double) frameTimeNanos / (double) 1'000'000'000;
|
||||
t.callVBlankListeners (timestampSec);
|
||||
}
|
||||
|
||||
static void handlePaintCallback (JNIEnv* env, AndroidComponentPeer& t, jobject canvas, jobject paint)
|
||||
|
|
|
|||
|
|
@ -573,7 +573,8 @@ private:
|
|||
|
||||
void onVBlank()
|
||||
{
|
||||
vBlankListeners.call ([] (auto& l) { l.onVBlank(); });
|
||||
const auto timestampSec = Time::getMillisecondCounterHiRes() / 1000.0;
|
||||
callVBlankListeners (timestampSec);
|
||||
|
||||
if (repainter != nullptr)
|
||||
repainter->dispatchDeferredRepaints();
|
||||
|
|
|
|||
|
|
@ -1920,9 +1920,9 @@ public:
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void onVBlank() override
|
||||
void onVBlank (double timestampSec) override
|
||||
{
|
||||
vBlankListeners.call ([] (auto& l) { l.onVBlank(); });
|
||||
callVBlankListeners (timestampSec);
|
||||
dispatchDeferredRepaints();
|
||||
|
||||
if (renderContext != nullptr)
|
||||
|
|
|
|||
|
|
@ -617,6 +617,11 @@ void ComponentPeer::forceDisplayUpdate()
|
|||
Desktop::getInstance().displays->refresh();
|
||||
}
|
||||
|
||||
void ComponentPeer::callVBlankListeners (double timestampSec)
|
||||
{
|
||||
vBlankListeners.call ([timestampSec] (auto& l) { l.onVBlank (timestampSec); });
|
||||
}
|
||||
|
||||
void ComponentPeer::globalFocusChanged ([[maybe_unused]] Component* comp)
|
||||
{
|
||||
refreshTextInputTarget();
|
||||
|
|
|
|||
|
|
@ -516,8 +516,12 @@ public:
|
|||
/** Destructor. */
|
||||
virtual ~VBlankListener() = default;
|
||||
|
||||
/** Called on every vertical blank of the display to which the peer is associated. */
|
||||
virtual void onVBlank() = 0;
|
||||
/** Called on every vertical blank of the display to which the peer is associated.
|
||||
|
||||
The timestampSec parameter is a monotonically increasing value expressed in seconds
|
||||
that corresponds to the time at which the next frame will be displayed.
|
||||
*/
|
||||
virtual void onVBlank (double timestampSec) = 0;
|
||||
};
|
||||
|
||||
/** Adds a VBlankListener. */
|
||||
|
|
@ -577,6 +581,7 @@ public:
|
|||
protected:
|
||||
//==============================================================================
|
||||
static void forceDisplayUpdate();
|
||||
void callVBlankListeners (double timestampSec);
|
||||
|
||||
Component& component;
|
||||
const int styleFlags;
|
||||
|
|
|
|||
|
|
@ -899,7 +899,7 @@ public:
|
|||
{
|
||||
connection.emplace (sharedDisplayLinks->registerFactory ([this] (CGDirectDisplayID display)
|
||||
{
|
||||
return [this, display]
|
||||
return [this, display] (double)
|
||||
{
|
||||
if (display == lastDisplay)
|
||||
triggerRepaint();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue