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(&registry, &Client::Registry::compositorAnnounced);
124     QSignalSpy shmSpy(&registry, &Client::Registry::shmAnnounced);
125     QSignalSpy presentationSpy(&registry, &Client::Registry::presentationManagerAnnounced);
126     QSignalSpy outputSpy(&registry, &Client::Registry::outputAnnounced);
127     QSignalSpy allAnnounced(&registry, &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(&registry, &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