1 /********************************************************************
2 Copyright © 2020 Roman Gilg <subdiff@gmail.com>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20 #include <QtTest>
21
22 #include "../../src/client/compositor.h"
23 #include "../../src/client/connection_thread.h"
24 #include "../../src/client/event_queue.h"
25 #include "../../src/client/output.h"
26 #include "../../src/client/presentation_time.h"
27 #include "../../src/client/registry.h"
28 #include "../../src/client/shm_pool.h"
29 #include "../../src/client/surface.h"
30
31 #include "../../server/buffer.h"
32 #include "../../server/compositor.h"
33 #include "../../server/display.h"
34 #include "../../server/presentation_time.h"
35 #include "../../server/surface.h"
36
37 using namespace Wrapland;
38
39 class TestPresentationTime : public QObject
40 {
41 Q_OBJECT
42 public:
43 explicit TestPresentationTime(QObject* parent = nullptr);
44 private Q_SLOTS:
45 void init();
46 void cleanup();
47
48 void testClockId();
49 void testPresented();
50 void testDiscarded();
51
52 private:
53 Server::Display* m_display;
54 Server::Compositor* m_serverCompositor;
55 Server::PresentationManager* m_serverPresentation;
56 Server::Output* m_serverOutput;
57
58 Client::ConnectionThread* m_connection;
59 Client::EventQueue* m_queue;
60 Client::Compositor* m_compositor;
61 Client::ShmPool* m_shm;
62 Client::PresentationManager* m_presentation;
63 Client::Output* m_output;
64
65 QThread* m_thread;
66 };
67
68 static const QString s_socketName = QStringLiteral("wrapland-test-wayland-compositor-0");
69
TestPresentationTime(QObject * parent)70 TestPresentationTime::TestPresentationTime(QObject* parent)
71 : QObject(parent)
72 , m_display(nullptr)
73 , m_serverCompositor(nullptr)
74 , m_serverPresentation(nullptr)
75 , m_serverOutput(nullptr)
76 , m_connection(nullptr)
77 , m_compositor(nullptr)
78 , m_thread(nullptr)
79 {
80 }
81
init()82 void TestPresentationTime::init()
83 {
84 qRegisterMetaType<Server::Surface*>();
85
86 m_display = new Server::Display(this);
87 m_display->setSocketName(s_socketName);
88 m_display->start();
89 QVERIFY(m_display->running());
90
91 m_display->createShm();
92
93 m_serverCompositor = m_display->createCompositor(m_display);
94 QVERIFY(m_serverCompositor);
95
96 m_serverPresentation = m_display->createPresentationManager(m_display);
97 QVERIFY(m_serverPresentation);
98
99 m_serverOutput = new Server::Output(m_display, m_display);
100 m_serverOutput->set_enabled(true);
101 m_serverOutput->done();
102
103 // Setup connection.
104 m_connection = new Client::ConnectionThread;
105 QSignalSpy establishedSpy(m_connection, &Client::ConnectionThread::establishedChanged);
106 m_connection->setSocketName(s_socketName);
107
108 m_thread = new QThread(this);
109 m_connection->moveToThread(m_thread);
110 m_thread->start();
111
112 m_connection->establishConnection();
113 QVERIFY(establishedSpy.wait());
114
115 m_queue = new Client::EventQueue(this);
116 m_queue->setup(m_connection);
117 QVERIFY(m_queue->isValid());
118
119 QSignalSpy clientConnectedSpy(m_display, &Server::Display::clientConnected);
120 QVERIFY(clientConnectedSpy.isValid());
121
122 Client::Registry registry;
123 QSignalSpy compositorSpy(®istry, &Client::Registry::compositorAnnounced);
124 QSignalSpy shmSpy(®istry, &Client::Registry::shmAnnounced);
125 QSignalSpy presentationSpy(®istry, &Client::Registry::presentationManagerAnnounced);
126 QSignalSpy outputSpy(®istry, &Client::Registry::outputAnnounced);
127 QSignalSpy allAnnounced(®istry, &Client::Registry::interfacesAnnounced);
128 QVERIFY(compositorSpy.isValid());
129 QVERIFY(shmSpy.isValid());
130 QVERIFY(presentationSpy.isValid());
131 QVERIFY(outputSpy.isValid());
132 QVERIFY(allAnnounced.isValid());
133
134 registry.setEventQueue(m_queue);
135 registry.create(m_connection->display());
136 QVERIFY(registry.isValid());
137 registry.setup();
138
139 QVERIFY(allAnnounced.wait());
140 m_compositor = registry.createCompositor(compositorSpy.first().first().value<quint32>(),
141 compositorSpy.first().last().value<quint32>(),
142 this);
143 QVERIFY(m_compositor->isValid());
144
145 m_shm = registry.createShmPool(
146 shmSpy.first().first().value<quint32>(), shmSpy.first().last().value<quint32>(), this);
147 QVERIFY(m_shm->isValid());
148
149 m_presentation
150 = registry.createPresentationManager(presentationSpy.first().first().value<quint32>(),
151 presentationSpy.first().last().value<quint32>(),
152 this);
153 QVERIFY(m_presentation->isValid());
154
155 m_output = registry.createOutput(outputSpy.first().first().value<quint32>(),
156 outputSpy.first().last().value<quint32>(),
157 this);
158 QVERIFY(m_output->isValid());
159
160 QVERIFY(clientConnectedSpy.wait());
161 }
162
cleanup()163 void TestPresentationTime::cleanup()
164 {
165 delete m_output;
166 m_output = nullptr;
167 delete m_presentation;
168 m_presentation = nullptr;
169 delete m_shm;
170 m_shm = nullptr;
171 delete m_compositor;
172 m_compositor = nullptr;
173 delete m_queue;
174 m_queue = nullptr;
175
176 if (m_thread) {
177 m_thread->quit();
178 m_thread->wait();
179 delete m_thread;
180 m_thread = nullptr;
181 }
182 delete m_connection;
183 m_connection = nullptr;
184
185 delete m_display;
186 m_display = nullptr;
187 }
188
testClockId()189 void TestPresentationTime::testClockId()
190 {
191 Client::Registry registry;
192 Client::EventQueue queue;
193 queue.setup(m_connection);
194
195 QSignalSpy presentationSpy(®istry, &Client::Registry::presentationManagerAnnounced);
196 QVERIFY(presentationSpy.isValid());
197
198 registry.setEventQueue(&queue);
199 registry.create(m_connection->display());
200 QVERIFY(registry.isValid());
201 registry.setup();
202
203 m_serverPresentation->setClockId(2);
204 QCOMPARE(m_serverPresentation->clockId(), 2);
205
206 QVERIFY(presentationSpy.wait());
207 std::unique_ptr<Client::PresentationManager> presentation{
208 registry.createPresentationManager(presentationSpy.first().first().value<quint32>(),
209 presentationSpy.first().last().value<quint32>())};
210 QVERIFY(presentation->isValid());
211
212 QSignalSpy clockSpy(presentation.get(), &Client::PresentationManager::clockIdChanged);
213 QVERIFY(clockSpy.isValid());
214
215 QVERIFY(clockSpy.wait());
216 QCOMPARE(clockSpy.count(), 1);
217 QCOMPARE(presentation->clockId(), m_serverPresentation->clockId());
218
219 m_serverPresentation->setClockId(3);
220 QCOMPARE(m_serverPresentation->clockId(), 3);
221
222 QVERIFY(clockSpy.wait());
223 QCOMPARE(clockSpy.count(), 2);
224 QCOMPARE(presentation->clockId(), m_serverPresentation->clockId());
225 }
226
testPresented()227 void TestPresentationTime::testPresented()
228 {
229 QSignalSpy serverSurfaceCreated(m_serverCompositor, &Server::Compositor::surfaceCreated);
230 QVERIFY(serverSurfaceCreated.isValid());
231
232 auto surface = m_compositor->createSurface();
233 QVERIFY(serverSurfaceCreated.wait());
234
235 auto serverSurface = serverSurfaceCreated.first().first().value<Server::Surface*>();
236 QVERIFY(serverSurface);
237 QCOMPARE(serverSurface->state().damage, QRegion());
238 QVERIFY(!serverSurface->isMapped());
239
240 auto feedback = m_presentation->createFeedback(surface);
241
242 QSignalSpy committedSpy(serverSurface, &Server::Surface::committed);
243 QVERIFY(committedSpy.isValid());
244
245 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
246 img.fill(Qt::black);
247 auto buffer = m_shm->createBuffer(img);
248
249 surface->attachBuffer(buffer);
250 surface->damage(QRect(0, 0, 10, 10));
251 surface->commit(Client::Surface::CommitFlag::None);
252
253 QVERIFY(committedSpy.wait());
254 QCOMPARE(committedSpy.count(), 1);
255
256 serverSurface->setOutputs({m_serverOutput});
257 auto id = serverSurface->lockPresentation(m_serverOutput);
258 QVERIFY(id);
259
260 QSignalSpy presentedSpy(feedback, &Client::PresentationFeedback::presented);
261 QVERIFY(presentedSpy.isValid());
262
263 // Send feedback with some test values.
264 serverSurface->presentationFeedback(id,
265 1,
266 2,
267 3,
268 4,
269 5,
270 6,
271 Server::Surface::PresentationKind::Vsync
272 | Server::Surface::PresentationKind::ZeroCopy);
273
274 QVERIFY(presentedSpy.wait());
275 QCOMPARE(presentedSpy.count(), 1);
276
277 QCOMPARE(feedback->syncOutput(), m_output);
278
279 QCOMPARE(feedback->tvSecHi(), 1);
280 QCOMPARE(feedback->tvSecLo(), 2);
281 QCOMPARE(feedback->tvNsec(), 3);
282 QCOMPARE(feedback->refresh(), 4);
283 QCOMPARE(feedback->seqHi(), 5);
284 QCOMPARE(feedback->seqLo(), 6);
285 QCOMPARE(feedback->flags(),
286 Client::PresentationFeedback::Kind::Vsync
287 | Client::PresentationFeedback::Kind::ZeroCopy);
288
289 delete feedback;
290 delete surface;
291 }
292
testDiscarded()293 void TestPresentationTime::testDiscarded()
294 {
295 QSignalSpy serverSurfaceCreated(m_serverCompositor, &Server::Compositor::surfaceCreated);
296 QVERIFY(serverSurfaceCreated.isValid());
297
298 auto surface = m_compositor->createSurface();
299 QVERIFY(serverSurfaceCreated.wait());
300
301 auto serverSurface = serverSurfaceCreated.first().first().value<Server::Surface*>();
302 QVERIFY(serverSurface);
303 QCOMPARE(serverSurface->state().damage, QRegion());
304 QVERIFY(!serverSurface->isMapped());
305
306 auto feedback = m_presentation->createFeedback(surface);
307
308 QSignalSpy committedSpy(serverSurface, &Server::Surface::committed);
309 QVERIFY(committedSpy.isValid());
310
311 QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied);
312 img.fill(Qt::black);
313 auto buffer = m_shm->createBuffer(img);
314
315 surface->attachBuffer(buffer);
316 surface->damage(QRect(0, 0, 10, 10));
317 surface->commit(Client::Surface::CommitFlag::None);
318
319 QVERIFY(committedSpy.wait());
320 QCOMPARE(committedSpy.count(), 1);
321
322 serverSurface->setOutputs({m_serverOutput});
323 auto id = serverSurface->lockPresentation(m_serverOutput);
324 QVERIFY(id);
325
326 QSignalSpy presentedSpy(feedback, &Client::PresentationFeedback::presented);
327 QVERIFY(presentedSpy.isValid());
328 QSignalSpy discardedSpy(feedback, &Client::PresentationFeedback::discarded);
329 QVERIFY(discardedSpy.isValid());
330
331 // Send feedback with some test values.
332 serverSurface->presentationDiscarded(id);
333
334 QVERIFY(discardedSpy.wait());
335 QCOMPARE(discardedSpy.count(), 1);
336 QCOMPARE(presentedSpy.count(), 0);
337
338 QCOMPARE(feedback->syncOutput(), nullptr);
339
340 delete feedback;
341 delete surface;
342 }
343
344 QTEST_GUILESS_MAIN(TestPresentationTime)
345 #include "presentation_time.moc"
346