Loading...
Searching...
No Matches
RenderClock.hpp
1#pragma once
2#include <score_plugin_gfx_export.h>
3
4#include <QMetaObject>
5#include <QObject>
6
7#include <atomic>
8#include <functional>
9#include <thread>
10#include <vector>
11
12namespace score
13{
14class Timers;
15class HighResolutionTimer;
16}
17
18namespace score::gfx
19{
20class OutputNode;
21
40class SCORE_PLUGIN_GFX_EXPORT RenderClock
41{
42public:
43 enum class Kind
44 {
45 Timer, //< shared wall-timer at manualRenderingRate (the default)
46 DisplayVSync, //< display swap-chain vsync callback (push)
47 ExternalGenlock //< hardware genlock, e.g. a card's VBI
48 };
49
50 virtual ~RenderClock();
51
52 virtual Kind kind() const noexcept = 0;
53
60 virtual void start(std::function<void()> tick) = 0;
61
63 virtual void stop() = 0;
64};
65
76class SCORE_PLUGIN_GFX_EXPORT TimerClock final : public RenderClock
77{
78public:
86 TimerClock(score::Timers& timers, QObject* owner, double frequencyHz);
87 ~TimerClock() override;
88
89 Kind kind() const noexcept override { return Kind::Timer; }
90
91 double frequency() const noexcept { return m_frequency; }
92
93 // Coalesced set of outputs driven by this clock's shared timer.
94 void addOutput(OutputNode* o);
95 void removeOutput(OutputNode* o);
96 bool empty() const noexcept { return m_outputs.empty(); }
97 const std::vector<OutputNode*>& outputs() const noexcept { return m_outputs; }
98
99 void start(std::function<void()> tick) override;
100 void stop() override;
101
102private:
103 score::Timers& m_timers;
104 QObject* m_owner{};
105 double m_frequency{};
107 QMetaObject::Connection m_conn;
108 std::function<void()> m_tick;
109 std::vector<OutputNode*> m_outputs;
110
111 // Receiver context for the queued timeout connection. Destroying this (a
112 // member, so torn down with the TimerClock) removes any already-posted
113 // queued timeout events targeting it — QObject::disconnect() alone does not,
114 // which let a pending tick fire the lambda on this freed TimerClock during
115 // shutdown (heap-use-after-free, RenderClock.cpp `if(m_tick)`). Lives on the
116 // same (render) thread as m_owner since TimerClocks are built there, so the
117 // tick is still delivered on that thread.
118 QObject m_receiver;
119};
120
127class SCORE_PLUGIN_GFX_EXPORT DisplayVSyncClock final : public RenderClock
128{
129public:
130 explicit DisplayVSyncClock(OutputNode& output);
131 ~DisplayVSyncClock() override;
132
133 Kind kind() const noexcept override { return Kind::DisplayVSync; }
134
135 void start(std::function<void()> tick) override;
136 void stop() override;
137
138private:
139 OutputNode& m_output;
140};
141
168class SCORE_PLUGIN_GFX_EXPORT ExternalGenlockClock final : public RenderClock
169{
170public:
178 ExternalGenlockClock(QObject* owner, std::function<bool()> waitForNextTick);
179 ~ExternalGenlockClock() override;
180
181 Kind kind() const noexcept override { return Kind::ExternalGenlock; }
182
183 void start(std::function<void()> tick) override;
184 void stop() override;
185
186private:
187 void run();
188
189 QObject* m_owner{};
190 std::function<bool()> m_waitForNextTick;
191 std::function<void()> m_tick;
192 std::thread m_thread;
193 std::atomic<bool> m_running{false};
194 std::atomic<bool> m_exited{false};
195};
196}
Definition Timers.hpp:14
Definition Timers.hpp:38
Wraps ScreenNode's swap-chain vsync callback path (clock #1, push).
Definition RenderClock.hpp:128
Hardware-genlock render clock (opt-in): a card's output VBI.
Definition RenderClock.hpp:169
Base class for sink nodes (QWindow, spout, syphon, NDI output, ...)
Definition OutputNode.hpp:54
Abstract render clock.
Definition RenderClock.hpp:41
virtual void start(std::function< void()> tick)=0
Begin delivering ticks.
virtual void stop()=0
Stop delivering ticks and release the underlying tick source.
Wraps GfxContext's shared wall-timer (clock #2, the default).
Definition RenderClock.hpp:77
Graphics rendering pipeline for ossia score.
Definition Filter/PreviewWidget.hpp:11
Base toolkit upon which the software is built.
Definition Application.cpp:116