1/****************************************************************************
2**
3** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29// TODO Remove in Qt6
30#include <QtCore/qcompilerdetection.h>
31QT_WARNING_DISABLE_DEPRECATED
32
33#include <QtTest/QTest>
34#include <qbackendnodetester.h>
35#include <Qt3DRender/private/buffer_p.h>
36#include <Qt3DRender/private/qbuffer_p.h>
37#include <Qt3DRender/private/buffermanager_p.h>
38#include <Qt3DCore/qpropertyupdatedchange.h>
39#include <Qt3DCore/private/qbackendnode_p.h>
40#include "testpostmanarbiter.h"
41#include "testrenderer.h"
42
43class TestFunctor : public Qt3DRender::QBufferDataGenerator
44{
45public:
46 explicit TestFunctor(int size)
47 : m_size(size)
48 {}
49
50 QByteArray operator ()() final
51 {
52 return QByteArrayLiteral("454");
53 }
54
55 bool operator ==(const Qt3DRender::QBufferDataGenerator &other) const final
56 {
57 const TestFunctor *otherFunctor = Qt3DRender::functor_cast<TestFunctor>(other: &other);
58 if (otherFunctor != nullptr)
59 return otherFunctor->m_size == m_size;
60 return false;
61 }
62
63 QT3D_FUNCTOR(TestFunctor)
64
65private:
66 int m_size;
67};
68
69class tst_RenderBuffer : public Qt3DCore::QBackendNodeTester
70{
71 Q_OBJECT
72
73private Q_SLOTS:
74
75 void checkPeerPropertyMirroring()
76 {
77 // GIVEN
78 Qt3DRender::Render::Buffer renderBuffer;
79 Qt3DRender::QBuffer buffer;
80 Qt3DRender::Render::BufferManager bufferManager;
81 TestRenderer renderer;
82
83 buffer.setUsage(Qt3DRender::QBuffer::DynamicCopy);
84 buffer.setData(QByteArrayLiteral("Corvette"));
85 buffer.setDataGenerator(Qt3DRender::QBufferDataGeneratorPtr(new TestFunctor(883)));
86
87 // WHEN
88 renderBuffer.setRenderer(&renderer);
89 renderBuffer.setManager(&bufferManager);
90 simulateInitializationSync(frontend: &buffer, backend: &renderBuffer);
91
92 // THEN
93 QCOMPARE(renderBuffer.peerId(), buffer.id());
94 QCOMPARE(renderBuffer.isDirty(), true);
95 QCOMPARE(renderBuffer.usage(), buffer.usage());
96 QCOMPARE(renderBuffer.data(), buffer.data());
97 QCOMPARE(renderBuffer.dataGenerator(), buffer.dataGenerator());
98 QVERIFY(*renderBuffer.dataGenerator() == *buffer.dataGenerator());
99 QCOMPARE(renderBuffer.pendingBufferUpdates().size(), 1);
100 QCOMPARE(renderBuffer.pendingBufferUpdates().first().offset, -1);
101 }
102
103 void checkInitialAndCleanedUpState()
104 {
105 // GIVEN
106 Qt3DRender::Render::Buffer backendBuffer;
107 Qt3DRender::Render::BufferManager bufferManager;
108 TestRenderer renderer;
109
110 // THEN
111 QCOMPARE(backendBuffer.isDirty(), false);
112 QCOMPARE(backendBuffer.usage(), Qt3DRender::QBuffer::StaticDraw);
113 QVERIFY(backendBuffer.data().isEmpty());
114 QVERIFY(backendBuffer.peerId().isNull());
115 QVERIFY(backendBuffer.dataGenerator().isNull());
116 QVERIFY(backendBuffer.pendingBufferUpdates().empty());
117
118 // GIVEN
119 Qt3DRender::QBuffer frontendBuffer;
120
121 // WHEN
122 backendBuffer.setManager(&bufferManager);
123 backendBuffer.setRenderer(&renderer);
124 simulateInitializationSync(frontend: &frontendBuffer, backend: &backendBuffer);
125
126 // THEN
127 QCOMPARE(backendBuffer.isDirty(), true);
128 QCOMPARE(backendBuffer.usage(), Qt3DRender::QBuffer::StaticDraw);
129 QVERIFY(backendBuffer.data().isEmpty());
130 QVERIFY(backendBuffer.dataGenerator().isNull());
131 QVERIFY(backendBuffer.pendingBufferUpdates().empty());
132
133 // WHEN
134 frontendBuffer.setUsage(Qt3DRender::QBuffer::DynamicCopy);
135 frontendBuffer.setData(QByteArrayLiteral("C7KR4"));
136 frontendBuffer.setDataGenerator(Qt3DRender::QBufferDataGeneratorPtr(new TestFunctor(73)));
137 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
138
139 // THEN
140 QCOMPARE(backendBuffer.usage(), Qt3DRender::QBuffer::DynamicCopy);
141 QCOMPARE(backendBuffer.isDirty(), true);
142 QCOMPARE(backendBuffer.data(), QByteArrayLiteral("C7KR4"));
143 QVERIFY(!backendBuffer.dataGenerator().isNull());
144 QVERIFY(!backendBuffer.pendingBufferUpdates().empty());
145
146 // WHEN
147 frontendBuffer.updateData(offset: 2, QByteArrayLiteral("LS5"));
148 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
149
150 // THEN
151 QCOMPARE(backendBuffer.isDirty(), true);
152 QCOMPARE(backendBuffer.data(), QByteArrayLiteral("C7LS5"));
153 // WHEN
154 backendBuffer.cleanup();
155
156 // THEN
157 QCOMPARE(backendBuffer.isDirty(), false);
158 QCOMPARE(backendBuffer.usage(), Qt3DRender::QBuffer::StaticDraw);
159 QVERIFY(backendBuffer.data().isEmpty());
160 QVERIFY(backendBuffer.dataGenerator().isNull());
161 QVERIFY(backendBuffer.pendingBufferUpdates().empty());
162 }
163
164
165 void checkForceFullUploadOnFirstTime()
166 {
167 // GIVEN
168 Qt3DRender::Render::Buffer backendBuffer;
169 Qt3DRender::Render::BufferManager bufferManager;
170 TestRenderer renderer;
171 Qt3DRender::QBuffer frontendBuffer;
172
173 QByteArray data("111456789\0");
174
175 frontendBuffer.setData(data);
176 frontendBuffer.updateData(offset: 1, bytes: QByteArray("23\0"));
177
178 // THEN
179 QCOMPARE(frontendBuffer.data(), QByteArray("123456789\0"));
180
181 // WHEN
182 backendBuffer.setManager(&bufferManager);
183 backendBuffer.setRenderer(&renderer);
184 simulateInitializationSync(frontend: &frontendBuffer, backend: &backendBuffer);
185
186 // THEN
187 QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1);
188 Qt3DRender::QBufferUpdate fullUpdate = backendBuffer.pendingBufferUpdates().first();
189 QCOMPARE(fullUpdate.offset, -1);
190 QVERIFY(fullUpdate.data.isEmpty());
191 QCOMPARE(frontendBuffer.data(), backendBuffer.data());
192
193 backendBuffer.pendingBufferUpdates().clear();
194
195 // WHEN
196 frontendBuffer.updateData(offset: 1, bytes: QByteArray("00\0"));
197 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
198
199 // THEN
200 QCOMPARE(frontendBuffer.data(), QByteArray("100456789\0"));
201 QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1);
202 fullUpdate = backendBuffer.pendingBufferUpdates().first();
203 QCOMPARE(fullUpdate.offset, 1);
204 QCOMPARE(fullUpdate.data, QByteArray("00\0"));
205 QCOMPARE(frontendBuffer.data(), backendBuffer.data());
206
207 // WHEN
208 frontendBuffer.updateData(offset: 1, bytes: QByteArray("22\0"));
209 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: true);
210
211 // THEN
212 QCOMPARE(frontendBuffer.data(), QByteArray("122456789\0"));
213 fullUpdate = backendBuffer.pendingBufferUpdates().first();
214 QCOMPARE(fullUpdate.offset, -1);
215 QVERIFY(fullUpdate.data.isEmpty());
216 QCOMPARE(frontendBuffer.data(), backendBuffer.data());
217 }
218
219 void checkPropertyChanges()
220 {
221 // GIVEN
222 TestRenderer renderer;
223 Qt3DRender::QBuffer frontendBuffer;
224 Qt3DRender::Render::Buffer backendBuffer;
225 backendBuffer.setRenderer(&renderer);
226 simulateInitializationSync(frontend: &frontendBuffer, backend: &backendBuffer);
227
228 // THEN
229 QVERIFY(backendBuffer.data().isEmpty());
230 QVERIFY(backendBuffer.usage() != Qt3DRender::QBuffer::DynamicRead);
231 QVERIFY(!backendBuffer.isDirty());
232 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
233 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
234
235 // WHEN
236 frontendBuffer.setUsage(Qt3DRender::QBuffer::DynamicRead);
237 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
238
239 // THEN
240 QCOMPARE(backendBuffer.usage(), Qt3DRender::QBuffer::DynamicRead);
241 QVERIFY(backendBuffer.isDirty());
242
243 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
244 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
245
246 backendBuffer.unsetDirty();
247 QVERIFY(!backendBuffer.isDirty());
248
249 // WHEN
250 frontendBuffer.setData(QByteArrayLiteral("LS9SL"));
251 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
252
253 // THEN
254 QCOMPARE(backendBuffer.data(), QByteArrayLiteral("LS9SL"));
255 QVERIFY(backendBuffer.isDirty());
256 QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1);
257 QCOMPARE(backendBuffer.pendingBufferUpdates().first().offset, -1);
258
259 backendBuffer.pendingBufferUpdates().clear();
260
261 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
262 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
263
264 backendBuffer.unsetDirty();
265 QVERIFY(!backendBuffer.isDirty());
266
267 // WHEN
268 Qt3DRender::QBufferDataGeneratorPtr functor(new TestFunctor(355));
269 frontendBuffer.setDataGenerator(functor);
270 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
271
272 // THEN
273 QCOMPARE(backendBuffer.dataGenerator(), functor);
274 QVERIFY(backendBuffer.isDirty());
275
276 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
277 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
278
279 backendBuffer.unsetDirty();
280 QVERIFY(!backendBuffer.isDirty());
281
282 // WHEN
283 frontendBuffer.setSyncData(true);
284 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
285
286 // THEN
287 QCOMPARE(backendBuffer.isSyncData(), true);
288 QVERIFY(!backendBuffer.isDirty());
289
290 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
291 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
292
293 // WHEN
294 TestArbiter arbiter;
295 Qt3DCore::QBackendNodePrivate::get(n: &backendBuffer)->setArbiter(&arbiter);
296 backendBuffer.executeFunctor();
297
298 // THEN
299 QCOMPARE(arbiter.events.count(), 0);
300 QCOMPARE(backendBuffer.pendingBufferUpdates().size(), 1);
301 QCOMPARE(backendBuffer.pendingBufferUpdates().first().offset, -1);
302
303 arbiter.events.clear();
304 backendBuffer.pendingBufferUpdates().clear();
305
306 // WHEN
307 frontendBuffer.updateData(offset: 2, QByteArrayLiteral("LS5"));
308 backendBuffer.syncFromFrontEnd(frontEnd: &frontendBuffer, firstTime: false);
309
310 // THEN
311 QVERIFY(!backendBuffer.pendingBufferUpdates().empty());
312 QCOMPARE(backendBuffer.pendingBufferUpdates().first().offset, 2);
313 QVERIFY(backendBuffer.isDirty());
314
315 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::BuffersDirty);
316 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
317
318 backendBuffer.unsetDirty();
319 QVERIFY(!backendBuffer.isDirty());
320 }
321
322 void checkBufferManagerReferenceCount()
323 {
324 // GIVEN
325 Qt3DRender::Render::Buffer renderBuffer;
326 Qt3DRender::QBuffer buffer;
327 Qt3DRender::Render::BufferManager bufferManager;
328 TestRenderer renderer;
329
330 // WHEN
331 renderBuffer.setRenderer(&renderer);
332 renderBuffer.setManager(&bufferManager);
333 simulateInitializationSync(frontend: &buffer, backend: &renderBuffer);
334
335 // THEN
336 QVERIFY(bufferManager.takeBuffersToRelease().empty());
337
338 // WHEN
339 bufferManager.removeBufferReference(bufferId: renderBuffer.peerId());
340 auto buffers = bufferManager.takeBuffersToRelease();
341
342 // THEN
343 QVERIFY(buffers.size() == 1);
344 QVERIFY(buffers.first() == renderBuffer.peerId());
345 QVERIFY(bufferManager.takeBuffersToRelease().empty());
346 }
347
348 void checkSetRendererDirtyOnInitialization()
349 {
350 // GIVEN
351 Qt3DRender::Render::Buffer renderBuffer;
352 Qt3DRender::QBuffer buffer;
353 Qt3DRender::Render::BufferManager bufferManager;
354 TestRenderer renderer;
355
356 renderBuffer.setRenderer(&renderer);
357 renderBuffer.setManager(&bufferManager);
358
359 // THEN
360 QCOMPARE(renderer.dirtyBits(), 0);
361
362 // WHEN
363 simulateInitializationSync(frontend: &buffer, backend: &renderBuffer);
364
365 // THEN
366 QCOMPARE(renderer.dirtyBits(), Qt3DRender::Render::AbstractRenderer::BuffersDirty);
367 }
368
369 void checkHandlesMultipleUpdates()
370 {
371 // GIVEN
372 Qt3DRender::Render::Buffer renderBuffer;
373 Qt3DRender::QBuffer buffer;
374 Qt3DRender::Render::BufferManager bufferManager;
375 TestRenderer renderer;
376
377 const QByteArray initData("000000");
378 buffer.setData(initData);
379
380 renderBuffer.setRenderer(&renderer);
381 renderBuffer.setManager(&bufferManager);
382
383 simulateInitializationSync(frontend: &buffer, backend: &renderBuffer);
384
385 // THEN
386 QCOMPARE(renderBuffer.data(), initData);
387 renderBuffer.pendingBufferUpdates().clear();
388
389 // WHEN
390 buffer.updateData(offset: 0, bytes: QByteArray("012"));
391 buffer.updateData(offset: 3, bytes: QByteArray("345"));
392 renderBuffer.syncFromFrontEnd(frontEnd: &buffer, firstTime: false);
393
394 // THEN
395 QCOMPARE(renderBuffer.pendingBufferUpdates().size(), 2);
396 QCOMPARE(renderBuffer.pendingBufferUpdates().first().offset, 0);
397 QCOMPARE(renderBuffer.pendingBufferUpdates().first().data, QByteArray("012"));
398 QCOMPARE(renderBuffer.pendingBufferUpdates().last().offset, 3);
399 QCOMPARE(renderBuffer.pendingBufferUpdates().last().data, QByteArray("345"));
400 QCOMPARE(renderBuffer.data(), QByteArray("012345"));
401 }
402};
403
404
405QTEST_APPLESS_MAIN(tst_RenderBuffer)
406
407#include "tst_buffer.moc"
408

source code of qt3d/tests/auto/render/buffer/tst_buffer.cpp