1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite 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 | #include <qtest.h> |
30 | |
31 | #include <QtQuick/qquickitem.h> |
32 | #include <QtQuick/qquickview.h> |
33 | #include <QtQuick/qsgrendererinterface.h> |
34 | #include <QtGui/qopenglcontext.h> |
35 | #include <QtGui/qopenglfunctions.h> |
36 | |
37 | #include "../../shared/util.h" |
38 | |
39 | #include <QtGui/private/qguiapplication_p.h> |
40 | #include <QtGui/qpa/qplatformintegration.h> |
41 | |
42 | class tst_QQuickItemLayer: public QQmlDataTest |
43 | { |
44 | Q_OBJECT |
45 | public: |
46 | tst_QQuickItemLayer(); |
47 | |
48 | QImage runTest(const QString &fileName) |
49 | { |
50 | QQuickView view; |
51 | view.setSource(testFileUrl(fileName)); |
52 | |
53 | view.showNormal(); |
54 | return QTest::qWaitForWindowExposed(window: &view) |
55 | ? view.grabWindow() : QImage(); |
56 | } |
57 | |
58 | private slots: |
59 | void initTestCase() override; |
60 | void layerEnabled(); |
61 | void layerSmooth(); |
62 | #if QT_CONFIG(opengl) |
63 | void layerMipmap(); |
64 | void layerEffect(); |
65 | #endif |
66 | void layerVisibility_data(); |
67 | void layerVisibility(); |
68 | |
69 | void layerSourceRect(); |
70 | |
71 | void layerZOrder_data(); |
72 | void layerZOrder(); |
73 | |
74 | void layerIsTextureProvider(); |
75 | |
76 | void changeZOrder_data(); |
77 | void changeZOrder(); |
78 | |
79 | void toggleLayerAndEffect(); |
80 | void disableLayer(); |
81 | void changeSamplerName(); |
82 | void itemEffect(); |
83 | void rectangleEffect(); |
84 | |
85 | void textureMirroring_data(); |
86 | void textureMirroring(); |
87 | |
88 | private: |
89 | void mirroringCheck(int mirroring, int x, bool shouldMirror, const QImage &fb); |
90 | |
91 | bool m_isMesaSoftwareRasterizer = false; |
92 | int m_mesaVersion = 0; |
93 | bool m_isOpenGLRenderer = true; |
94 | }; |
95 | |
96 | tst_QQuickItemLayer::tst_QQuickItemLayer() { } |
97 | |
98 | void tst_QQuickItemLayer::initTestCase() |
99 | { |
100 | QQmlDataTest::initTestCase(); |
101 | #if QT_CONFIG(opengl) |
102 | if (QGuiApplicationPrivate::platformIntegration()->hasCapability(cap: QPlatformIntegration::OpenGL)) { |
103 | QWindow window; |
104 | QOpenGLContext context; |
105 | window.setSurfaceType(QWindow::OpenGLSurface); |
106 | window.create(); |
107 | QVERIFY(context.create()); |
108 | QVERIFY(context.makeCurrent(&window)); |
109 | const char *vendor = (const char *)context.functions()->glGetString(GL_VENDOR); |
110 | const char *renderer = (const char *)context.functions()->glGetString(GL_RENDERER); |
111 | m_isMesaSoftwareRasterizer = strcmp(s1: vendor, s2: "Mesa Project" ) == 0 |
112 | && strcmp(s1: renderer, s2: "Software Rasterizer" ) == 0; |
113 | if (m_isMesaSoftwareRasterizer) { |
114 | // Expects format: <OpenGL version> Mesa <Mesa version>[-devel] [...] |
115 | const char *version = (const char *)context.functions()->glGetString(GL_VERSION); |
116 | QList<QByteArray> list = QByteArray(version).split(sep: ' '); |
117 | if (list.size() >= 3) { |
118 | list = list.at(i: 2).split(sep: '-').at(i: 0).split(sep: '.'); |
119 | int major = 0; |
120 | int minor = 0; |
121 | int patch = 0; |
122 | if (list.size() >= 1) |
123 | major = list.at(i: 0).toInt(); |
124 | if (list.size() >= 2) |
125 | minor = list.at(i: 1).toInt(); |
126 | if (list.size() >= 3) |
127 | patch = list.at(i: 2).toInt(); |
128 | m_mesaVersion = QT_VERSION_CHECK(major, minor, patch); |
129 | } |
130 | } |
131 | window.create(); |
132 | } |
133 | #endif |
134 | QQuickView view; |
135 | view.showNormal(); |
136 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
137 | if (view.rendererInterface()->graphicsApi() != QSGRendererInterface::OpenGL) |
138 | m_isOpenGLRenderer = false; |
139 | } |
140 | |
141 | // The test draws a red and a blue box next to each other and tests that the |
142 | // output is still red and blue on the left and right and a combination of |
143 | // the two in the middle. |
144 | |
145 | void tst_QQuickItemLayer::layerSmooth() |
146 | { |
147 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
148 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
149 | |
150 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
151 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
152 | QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms" ); |
153 | |
154 | QImage fb = runTest(fileName: "Smooth.qml" ); |
155 | QVERIFY(!fb.size().isEmpty()); |
156 | QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); |
157 | QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0, 0xff)); |
158 | |
159 | uint pixel = fb.pixel(x: fb.width() / 2, y: 0); |
160 | QVERIFY(qRed(pixel) > 0); |
161 | QVERIFY(qBlue(pixel) > 0); |
162 | } |
163 | |
164 | |
165 | |
166 | // The test draws a gradient at a small size into a layer and scales the |
167 | // layer. If the layer is enabled there should be very visible bands in |
168 | // the gradient. |
169 | |
170 | void tst_QQuickItemLayer::layerEnabled() |
171 | { |
172 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
173 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
174 | |
175 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
176 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
177 | QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms" ); |
178 | |
179 | QImage fb = runTest(fileName: "Enabled.qml" ); |
180 | QVERIFY(!fb.size().isEmpty()); |
181 | // Verify the banding |
182 | QCOMPARE(fb.pixel(0, 0), fb.pixel(0, 1)); |
183 | // Verify the gradient |
184 | QVERIFY(fb.pixel(0, 0) != fb.pixel(0, fb.height() - 1)); |
185 | } |
186 | |
187 | #if QT_CONFIG(opengl) |
188 | // The test draws a one pixel wide line and scales it down by more than a a factor 2 |
189 | // If mipmpping works, the pixels should be gray, not white or black |
190 | |
191 | void tst_QQuickItemLayer::layerMipmap() |
192 | { |
193 | if (m_isMesaSoftwareRasterizer) |
194 | QSKIP("Mipmapping does not work with the Mesa Software Rasterizer." ); |
195 | |
196 | QImage fb = runTest(fileName: "Mipmap.qml" ); |
197 | QVERIFY(fb.pixel(0, 0) != 0xff000000); |
198 | QVERIFY(fb.pixel(0, 0) != 0xffffffff); |
199 | } |
200 | |
201 | |
202 | |
203 | // The test implements an rgb swapping effect sourced from a blue rectangle. The |
204 | // resulting pixel should be red |
205 | |
206 | void tst_QQuickItemLayer::layerEffect() |
207 | { |
208 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
209 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
210 | |
211 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
212 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
213 | QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms" ); |
214 | |
215 | QImage fb = runTest(fileName: "Effect.qml" ); |
216 | QVERIFY(!fb.size().isEmpty()); |
217 | QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); |
218 | QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); |
219 | } |
220 | #endif |
221 | |
222 | // The test draws a rectangle and verifies that there is padding on each side |
223 | // as the source rect spans outside the item. The padding is verified using |
224 | // a shader that pads transparent to blue. Everything else is red. |
225 | void tst_QQuickItemLayer::layerSourceRect() |
226 | { |
227 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
228 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
229 | |
230 | if (!m_isOpenGLRenderer) |
231 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
232 | |
233 | QImage fb = runTest(fileName: "SourceRect.qml" ); |
234 | QVERIFY(!fb.size().isEmpty()); |
235 | |
236 | // Check that the edges are converted to blue |
237 | QCOMPARE(fb.pixel(0, 0), qRgb(0, 0, 0xff)); |
238 | QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0, 0xff)); |
239 | QCOMPARE(fb.pixel(0, fb.height() - 1), qRgb(0, 0, 0xff)); |
240 | QCOMPARE(fb.pixel(fb.width() - 1, fb.height() - 1), qRgb(0, 0, 0xff)); |
241 | |
242 | // The center pixel should be red |
243 | QCOMPARE(fb.pixel(fb.width() / 2, fb.height() / 2), qRgb(0xff, 0, 0)); |
244 | } |
245 | |
246 | |
247 | |
248 | // Same as the effect test up above, but this time use the item |
249 | // directly in a stand alone ShaderEffect |
250 | void tst_QQuickItemLayer::layerIsTextureProvider() |
251 | { |
252 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
253 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
254 | |
255 | if (!m_isOpenGLRenderer) |
256 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
257 | |
258 | QImage fb = runTest(fileName: "TextureProvider.qml" ); |
259 | QVERIFY(!fb.size().isEmpty()); |
260 | QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); |
261 | QCOMPARE(fb.pixel(fb.width() - 1, 0), qRgb(0, 0xff, 0)); |
262 | } |
263 | |
264 | |
265 | void tst_QQuickItemLayer::layerVisibility_data() |
266 | { |
267 | QTest::addColumn<bool>(name: "visible" ); |
268 | QTest::addColumn<bool>(name: "effect" ); |
269 | QTest::addColumn<qreal>(name: "opacity" ); |
270 | |
271 | QTest::newRow(dataTag: "!effect, !visible, a=1" ) << false << false << 1.; |
272 | QTest::newRow(dataTag: "!effect, visible, a=1" ) << false << true << 1.; |
273 | QTest::newRow(dataTag: "effect, !visible, a=1" ) << true << false << 1.; |
274 | QTest::newRow(dataTag: "effect, visible, a=1" ) << true << true << 1.; |
275 | |
276 | QTest::newRow(dataTag: "!effect, !visible, a=.5" ) << false << false << .5; |
277 | QTest::newRow(dataTag: "!effect, visible, a=.5" ) << false << true << .5; |
278 | QTest::newRow(dataTag: "effect, !visible, a=.5" ) << true << false << .5; |
279 | QTest::newRow(dataTag: "effect, visible, a=.5" ) << true << true << .5; |
280 | |
281 | QTest::newRow(dataTag: "!effect, !visible, a=0" ) << false << false << 0.; |
282 | QTest::newRow(dataTag: "!effect, visible, a=0" ) << false << true << 0.; |
283 | QTest::newRow(dataTag: "effect, !visible, a=0" ) << true << false << 0.; |
284 | QTest::newRow(dataTag: "effect, visible, a=0" ) << true << true << 0.; |
285 | } |
286 | |
287 | void tst_QQuickItemLayer::layerVisibility() |
288 | { |
289 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
290 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
291 | |
292 | if (!m_isOpenGLRenderer) |
293 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
294 | |
295 | QFETCH(bool, visible); |
296 | QFETCH(bool, effect); |
297 | QFETCH(qreal, opacity); |
298 | |
299 | QQuickView view; |
300 | view.setSource(testFileUrl(fileName: "Visible.qml" )); |
301 | |
302 | QQuickItem *child = view.contentItem()->childItems().at(i: 0); |
303 | child->setProperty(name: "layerVisible" , value: visible); |
304 | child->setProperty(name: "layerEffect" , value: effect); |
305 | child->setProperty(name: "layerOpacity" , value: opacity); |
306 | |
307 | view.show(); |
308 | |
309 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
310 | |
311 | QImage fb = view.grabWindow(); |
312 | uint pixel = fb.pixel(x: 0, y: 0); |
313 | |
314 | if (!visible || opacity == 0) { |
315 | QCOMPARE(pixel, qRgb(0xff, 0xff, 0xff)); |
316 | } else if (effect) { |
317 | QCOMPARE(qRed(pixel), 0xff); |
318 | QVERIFY(qGreen(pixel) < 0xff); |
319 | QVERIFY(qBlue(pixel) < 0xff); |
320 | } else { // no effect |
321 | QCOMPARE(qBlue(pixel), 0xff); |
322 | QVERIFY(qGreen(pixel) < 0xff); |
323 | QVERIFY(qRed(pixel) < 0xff); |
324 | } |
325 | } |
326 | |
327 | |
328 | |
329 | |
330 | void tst_QQuickItemLayer::layerZOrder_data() |
331 | { |
332 | QTest::addColumn<bool>(name: "effect" ); |
333 | |
334 | QTest::newRow(dataTag: "!effect" ) << false; |
335 | QTest::newRow(dataTag: "effect" ) << true; |
336 | } |
337 | |
338 | void tst_QQuickItemLayer::layerZOrder() |
339 | { |
340 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
341 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
342 | |
343 | if (!m_isOpenGLRenderer) |
344 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
345 | |
346 | QFETCH(bool, effect); |
347 | |
348 | QQuickView view; |
349 | view.setSource(testFileUrl(fileName: "ZOrder.qml" )); |
350 | |
351 | QQuickItem *child = view.contentItem()->childItems().at(i: 0); |
352 | child->setProperty(name: "layerEffect" , value: effect); |
353 | |
354 | view.show(); |
355 | |
356 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
357 | |
358 | QImage fb = view.grabWindow(); |
359 | |
360 | QCOMPARE(fb.pixel(50, 50), qRgb(0, 0, 0xff)); |
361 | QCOMPARE(fb.pixel(150, 150), qRgb(0, 0xff, 00)); |
362 | |
363 | } |
364 | |
365 | void tst_QQuickItemLayer::changeZOrder_data() |
366 | { |
367 | QTest::addColumn<bool>(name: "layered" ); |
368 | QTest::addColumn<bool>(name: "effect" ); |
369 | |
370 | QTest::newRow(dataTag: "layered, effect" ) << true << true; |
371 | QTest::newRow(dataTag: "layered, !effect" ) << true << false; |
372 | QTest::newRow(dataTag: "!layered" ) << false << false; |
373 | } |
374 | |
375 | void tst_QQuickItemLayer::changeZOrder() |
376 | { |
377 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
378 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
379 | |
380 | if (!m_isOpenGLRenderer) |
381 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
382 | |
383 | QFETCH(bool, layered); |
384 | QFETCH(bool, effect); |
385 | |
386 | QQuickView view; |
387 | view.setSource(testFileUrl(fileName: "ZOrderChange.qml" )); |
388 | |
389 | QQuickItem *child = view.contentItem()->childItems().at(i: 0); |
390 | child->setProperty(name: "layerEnabled" , value: layered); |
391 | child->setProperty(name: "layerEffect" , value: effect); |
392 | child->setProperty(name: "layerZ" , value: 1); |
393 | |
394 | view.show(); |
395 | |
396 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
397 | |
398 | QImage fb = view.grabWindow(); |
399 | |
400 | QRgb topLeft = fb.pixel(x: 50, y: 50); |
401 | QRgb topRight = fb.pixel(x: 150, y: 50); |
402 | QRgb bottomLeft = fb.pixel(x: 50, y: 150); |
403 | QRgb bottomRight = fb.pixel(x: 150, y: 150); |
404 | |
405 | QCOMPARE(bottomLeft, qRgb(0, 0, 0xff)); |
406 | |
407 | if (layered) { |
408 | QCOMPARE(topLeft, qRgb(0, 0xff, 0xff)); |
409 | } else { |
410 | QCOMPARE(qGreen(topLeft), 0xff); |
411 | QVERIFY(qAbs(qRed(topLeft) - 0x3f) < 4); |
412 | QVERIFY(qAbs(qBlue(topLeft) - 0xbf) < 4); |
413 | } |
414 | |
415 | if (layered && effect) { |
416 | QCOMPARE(qRed(topRight), 0xff); |
417 | QCOMPARE(qGreen(topRight), 0x00); |
418 | QVERIFY(qAbs(qBlue(topRight) - 0x7f) < 4); |
419 | |
420 | QVERIFY(qAbs(qRed(bottomRight) - 0x7f) < 4); |
421 | QCOMPARE(qBlue(bottomRight), 0xff); |
422 | QVERIFY(qAbs(qGreen(bottomRight) - 0x7f) < 4); |
423 | } else { |
424 | QCOMPARE(qRed(topRight), 0xff); |
425 | QCOMPARE(qBlue(topRight), 0x00); |
426 | QVERIFY(qAbs(qGreen(topRight) - 0x7f) < 4); |
427 | |
428 | QVERIFY(qAbs(qRed(bottomRight) - 0x7f) < 4); |
429 | QCOMPARE(qGreen(bottomRight), 0xff); |
430 | QVERIFY(qAbs(qBlue(bottomRight) - 0x7f) < 4); |
431 | } |
432 | } |
433 | |
434 | void tst_QQuickItemLayer::toggleLayerAndEffect() |
435 | { |
436 | // This test passes if it doesn't crash. |
437 | runTest(fileName: "ToggleLayerAndEffect.qml" ); |
438 | } |
439 | |
440 | void tst_QQuickItemLayer::disableLayer() |
441 | { |
442 | // This test passes if it doesn't crash. |
443 | runTest(fileName: "DisableLayer.qml" ); |
444 | } |
445 | |
446 | void tst_QQuickItemLayer::changeSamplerName() |
447 | { |
448 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
449 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
450 | |
451 | if (!m_isOpenGLRenderer) |
452 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
453 | |
454 | QImage fb = runTest(fileName: "SamplerNameChange.qml" ); |
455 | QVERIFY(!fb.size().isEmpty()); |
456 | QCOMPARE(fb.pixel(0, 0), qRgb(0, 0, 0xff)); |
457 | } |
458 | |
459 | void tst_QQuickItemLayer::itemEffect() |
460 | { |
461 | if (m_isMesaSoftwareRasterizer && m_mesaVersion < QT_VERSION_CHECK(7, 11, 0)) |
462 | QSKIP("Mesa Software Rasterizer below version 7.11 does not render this test correctly." ); |
463 | if (!m_isOpenGLRenderer) |
464 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
465 | |
466 | QImage fb = runTest(fileName: "ItemEffect.qml" ); |
467 | QVERIFY(!fb.size().isEmpty()); |
468 | QCOMPARE(fb.pixel(0, 0), qRgb(0xff, 0, 0)); |
469 | QCOMPARE(fb.pixel(199, 0), qRgb(0xff, 0, 0)); |
470 | QCOMPARE(fb.pixel(0, 199), qRgb(0, 0, 0xff)); |
471 | QCOMPARE(fb.pixel(199, 199), qRgb(0, 0, 0xff)); |
472 | } |
473 | |
474 | void tst_QQuickItemLayer::rectangleEffect() |
475 | { |
476 | if ((QGuiApplication::platformName() == QLatin1String("offscreen" )) |
477 | || (QGuiApplication::platformName() == QLatin1String("minimal" ))) |
478 | QSKIP("Skipping due to grabWindow not functional on offscreen/minimal platforms" ); |
479 | |
480 | QImage fb = runTest(fileName: "RectangleEffect.qml" ); |
481 | QVERIFY(!fb.size().isEmpty()); |
482 | QCOMPARE(fb.pixel(0, 0), qRgb(0, 0xff, 0)); |
483 | QCOMPARE(fb.pixel(199, 0), qRgb(0, 0xff, 0)); |
484 | QCOMPARE(fb.pixel(0, 199), qRgb(0, 0xff, 0)); |
485 | QCOMPARE(fb.pixel(199, 199), qRgb(0, 0xff, 0)); |
486 | |
487 | QCOMPARE(fb.pixel(100, 0), qRgb(0, 0, 0xff)); |
488 | QCOMPARE(fb.pixel(199, 100), qRgb(0, 0, 0xff)); |
489 | QCOMPARE(fb.pixel(100, 199), qRgb(0, 0, 0xff)); |
490 | QCOMPARE(fb.pixel(0, 100), qRgb(0, 0, 0xff)); |
491 | } |
492 | |
493 | void tst_QQuickItemLayer::textureMirroring_data() |
494 | { |
495 | QTest::addColumn<int>(name: "mirroring" ); |
496 | |
497 | QTest::newRow(dataTag: "no mirroring" ) << 0; |
498 | QTest::newRow(dataTag: "horizontal" ) << 1; |
499 | QTest::newRow(dataTag: "vertical" ) << 2; |
500 | QTest::newRow(dataTag: "horizontal | vertical" ) << 3; |
501 | } |
502 | |
503 | void tst_QQuickItemLayer::textureMirroring() |
504 | { |
505 | QFETCH(int, mirroring); |
506 | |
507 | if (!m_isOpenGLRenderer) |
508 | QSKIP("Only OpenGL Renderer supports GLSL ShaderEffects" ); |
509 | |
510 | QQuickView view; |
511 | view.setSource(testFileUrl(fileName: "TextureMirroring.qml" )); |
512 | |
513 | QQuickItem *child = view.contentItem()->childItems().at(i: 0); |
514 | child->setProperty(name: "mirroring" , value: mirroring); |
515 | |
516 | view.show(); |
517 | |
518 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
519 | |
520 | QImage fb = view.grabWindow(); |
521 | |
522 | // Mirroring should have no visual effect on layered item without shader effect |
523 | mirroringCheck(mirroring, x: 0, shouldMirror: false, fb); |
524 | |
525 | // Mirroring should have visual effect on layered item with shader effect |
526 | mirroringCheck(mirroring, x: 50, shouldMirror: true, fb); |
527 | |
528 | // Mirroring should have no visual effect on source item for ShaderEffectSource |
529 | mirroringCheck(mirroring, x: 100, shouldMirror: false, fb); |
530 | |
531 | // Mirroring should have no visual effect on ShaderEffectSource item |
532 | mirroringCheck(mirroring, x: 150, shouldMirror: false, fb); |
533 | |
534 | // Mirroring should have visual effect on ShaderEffect item itself |
535 | mirroringCheck(mirroring, x: 200, shouldMirror: true, fb); |
536 | } |
537 | |
538 | void tst_QQuickItemLayer::mirroringCheck(int mirroring, int x, bool shouldMirror, const QImage &fb) |
539 | { |
540 | int offset = 10; |
541 | int spacing = 25; |
542 | |
543 | if (shouldMirror) { |
544 | switch (mirroring) { |
545 | case 0: { // No mirroring -> Visually Y gets swapped, X is default |
546 | QCOMPARE(fb.pixel(x + offset, offset), qRgb(0, 0xff, 0)); |
547 | QCOMPARE(fb.pixel(x + offset + spacing, offset), qRgb(0, 0, 0xff)); |
548 | QCOMPARE(fb.pixel(x + offset, offset + spacing), qRgb(0, 0, 0)); |
549 | QCOMPARE(fb.pixel(x + offset + spacing, offset + spacing), qRgb(0xff, 0, 0)); |
550 | break; |
551 | } |
552 | case 1: { // Horizontal mirroring -> Visually both X and Y get swapped, as neither is default |
553 | QCOMPARE(fb.pixel(x + offset, offset), qRgb(0, 0, 0xff)); |
554 | QCOMPARE(fb.pixel(x + offset + spacing, offset), qRgb(0, 0xff, 0)); |
555 | QCOMPARE(fb.pixel(x + offset, offset + spacing), qRgb(0xff, 0, 0)); |
556 | QCOMPARE(fb.pixel(x + offset + spacing, offset + spacing), qRgb(0, 0, 0)); |
557 | break; |
558 | } |
559 | case 2: { // Vertical mirroring -> The default case, nothing gets swapped |
560 | QCOMPARE(fb.pixel(x + offset, offset), qRgb(0, 0, 0)); |
561 | QCOMPARE(fb.pixel(x + offset + spacing, offset), qRgb(0xff, 0, 0)); |
562 | QCOMPARE(fb.pixel(x + offset, offset + spacing), qRgb(0, 0xff, 0)); |
563 | QCOMPARE(fb.pixel(x + offset + spacing, offset + spacing), qRgb(0, 0, 0xff)); |
564 | break; |
565 | } |
566 | case 3: { // Both axes mirrored -> Visually X gets swapped, Y is default |
567 | QCOMPARE(fb.pixel(x + offset, offset), qRgb(0xff, 0, 0)); |
568 | QCOMPARE(fb.pixel(x + offset + spacing, offset), qRgb(0, 0, 0)); |
569 | QCOMPARE(fb.pixel(x + offset, offset + spacing), qRgb(0, 0, 0xff)); |
570 | QCOMPARE(fb.pixel(x + offset + spacing, offset + spacing), qRgb(0, 0xff, 0)); |
571 | break; |
572 | } |
573 | default: |
574 | qWarning() << "Invalid case!" ; |
575 | break; |
576 | } |
577 | } else { |
578 | QCOMPARE(fb.pixel(x + offset, offset), qRgb(0, 0, 0)); |
579 | QCOMPARE(fb.pixel(x + offset + spacing, offset), qRgb(0xff, 0, 0)); |
580 | QCOMPARE(fb.pixel(x + offset, offset + spacing), qRgb(0, 0xff, 0)); |
581 | QCOMPARE(fb.pixel(x + offset + spacing, offset + spacing), qRgb(0, 0, 0xff)); |
582 | } |
583 | } |
584 | |
585 | QTEST_MAIN(tst_QQuickItemLayer) |
586 | |
587 | #include "tst_qquickitemlayer.moc" |
588 | |