-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathvsyncthread.cpp
168 lines (143 loc) · 5.34 KB
/
vsyncthread.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include "vsyncthread.h"
#include <QThread>
#include <QTime>
#include <QtDebug>
#include "moc_vsyncthread.cpp"
#include "util/math.h"
#include "util/performancetimer.h"
#include "waveform/guitick.h"
VSyncThread::VSyncThread(QObject* pParent)
: QThread(pParent),
m_bDoRendering(true),
m_vSyncTypeChanged(false),
m_syncIntervalTimeMicros(33333), // 30 FPS
m_waitToSwapMicros(0),
m_vSyncMode(ST_TIMER),
m_syncOk(false),
m_droppedFrames(0),
m_swapWait(0),
m_displayFrameRate(60.0),
m_vSyncPerRendering(1) {
}
VSyncThread::~VSyncThread() {
m_bDoRendering = false;
m_semaVsyncSlot.release(2); // Two slots
wait();
//delete m_glw;
}
void VSyncThread::run() {
QThread::currentThread()->setObjectName("VSyncThread");
m_waitToSwapMicros = m_syncIntervalTimeMicros;
m_timer.start();
//qDebug() << "VSyncThread::run()";
while (m_bDoRendering) {
if (m_vSyncMode == ST_FREE) {
// for benchmark only!
// renders the waveform, Possible delayed due to anti tearing
emit vsyncRender();
m_semaVsyncSlot.acquire();
emit vsyncSwap(); // swaps the new waveform to front
m_semaVsyncSlot.acquire();
m_sinceLastSwap = m_timer.restart();
m_waitToSwapMicros = 1000;
usleep(1000);
} else { // if (m_vSyncMode == ST_TIMER) {
emit vsyncRender(); // renders the new waveform.
// wait until rendering was scheduled. It might be delayed due a
// pending swap (depends one driver vSync settings)
m_semaVsyncSlot.acquire();
// qDebug() << "ST_TIMER " << lastMicros << restMicros;
int remainingForSwap = m_waitToSwapMicros - static_cast<int>(
m_timer.elapsed().toIntegerMicros());
// waiting for interval by sleep
if (remainingForSwap > 100) {
usleep(remainingForSwap);
}
// swaps the new waveform to front in case of gl-wf
emit vsyncSwap();
// wait until swap occurred. It might be delayed due to driver vSync
// settings.
m_semaVsyncSlot.acquire();
// <- Assume we are VSynced here ->
m_sinceLastSwap = m_timer.restart();
int lastSwapTime = static_cast<int>(m_sinceLastSwap.toIntegerMicros());
if (remainingForSwap < 0) {
// Our swapping call was already delayed
// The real swap might happens on the following VSync, depending on driver settings
m_droppedFrames++; // Count as Real Time Error
}
// try to stay in right intervals
m_waitToSwapMicros = m_syncIntervalTimeMicros +
((m_waitToSwapMicros - lastSwapTime) % m_syncIntervalTimeMicros);
}
}
}
int VSyncThread::elapsed() {
return static_cast<int>(m_timer.elapsed().toIntegerMicros());
}
void VSyncThread::setSyncIntervalTimeMicros(int syncTime) {
m_syncIntervalTimeMicros = syncTime;
m_vSyncPerRendering = static_cast<int>(
round(m_displayFrameRate * m_syncIntervalTimeMicros / 1000));
}
void VSyncThread::setVSyncType(int type) {
if (type >= (int)VSyncThread::ST_COUNT) {
type = VSyncThread::ST_TIMER;
}
m_vSyncMode = (enum VSyncMode)type;
m_droppedFrames = 0;
m_vSyncTypeChanged = true;
}
int VSyncThread::toNextSyncMicros() {
int rest = m_waitToSwapMicros - static_cast<int>(m_timer.elapsed().toIntegerMicros());
// int math is fine here, because we do not expect times > 4.2 s
if (rest < 0) {
rest %= m_syncIntervalTimeMicros;
rest += m_syncIntervalTimeMicros;
}
return rest;
}
int VSyncThread::fromTimerToNextSyncMicros(const PerformanceTimer& timer) {
int difference = static_cast<int>(m_timer.difference(timer).toIntegerMicros());
// int math is fine here, because we do not expect times > 4.2 s
return difference + m_waitToSwapMicros;
}
int VSyncThread::droppedFrames() {
return m_droppedFrames;
}
void VSyncThread::vsyncSlotFinished() {
m_semaVsyncSlot.release();
}
void VSyncThread::getAvailableVSyncTypes(QList<QPair<int, QString>>* pList) {
for (int i = (int)VSyncThread::ST_TIMER; i < (int)VSyncThread::ST_COUNT; i++) {
//if (isAvailable(type)) // TODO
{
enum VSyncMode mode = (enum VSyncMode)i;
QString name;
switch (mode) {
case VSyncThread::ST_TIMER:
name = tr("Timer (Fallback)");
break;
case VSyncThread::ST_MESA_VBLANK_MODE_1:
name = tr("MESA vblank_mode = 1");
break;
case VSyncThread::ST_SGI_VIDEO_SYNC:
name = tr("Wait for Video sync");
break;
case VSyncThread::ST_OML_SYNC_CONTROL:
name = tr("Sync Control");
break;
case VSyncThread::ST_FREE:
name = tr("Free + 1 ms (for benchmark only)");
break;
default:
break;
}
QPair<int, QString > pair = QPair<int, QString >(i, name);
pList->append(pair);
}
}
}
mixxx::Duration VSyncThread::sinceLastSwap() const {
return m_sinceLastSwap;
}