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 <QtGui/qopenglcontext.h>
34#include <QtGui/qopenglframebufferobject.h>
35#include <QtGui/qopenglfunctions.h>
36
37#include <QtQuick/QQuickFramebufferObject>
38
39#include "../../shared/util.h"
40
41#ifndef GL_MAX_SAMPLES
42#define GL_MAX_SAMPLES 0x8D57
43#endif
44
45struct FrameInfo {
46 int renderCount;
47 int createFBOCount;
48 bool msaaSupported;
49 bool msaaEnabled;
50 QSize fboSize;
51} frameInfo;
52
53class ColorRenderer : public QQuickFramebufferObject::Renderer, protected QOpenGLFunctions
54{
55public:
56 void render();
57 void synchronize(QQuickFramebufferObject *item);
58 QOpenGLFramebufferObject *createFramebufferObject(const QSize &size);
59
60 QSize textureSize;
61 QColor color;
62 bool msaa;
63};
64
65class FBOItem : public QQuickFramebufferObject
66{
67 Q_OBJECT
68
69 Q_PROPERTY(bool msaa READ msaa WRITE setMsaa NOTIFY msaaChanged)
70 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
71
72 Q_PROPERTY(QSize textureSize READ textureSize WRITE setTextureSize NOTIFY textureSizeChanged)
73
74public:
75 Renderer *createRenderer() const { return new ColorRenderer(); }
76
77 void setColor(const QColor &color) { m_color = color; colorChanged(m_color); }
78 QColor color() const { return m_color; }
79
80 void setMsaa(bool msaa) { m_msaa = msaa; msaaChanged(m_msaa); }
81 bool msaa() const { return m_msaa; }
82
83 void setTextureSize(const QSize &size) { m_textureSize = size; textureSizeChanged(m_textureSize); }
84 QSize textureSize() const { return m_textureSize; }
85
86signals:
87 void colorChanged(const QColor &color);
88 void msaaChanged(bool msaa);
89 void textureSizeChanged(const QSize &size);
90
91public:
92 bool m_msaa;
93 QColor m_color;
94 QSize m_textureSize;
95
96};
97
98void ColorRenderer::render()
99{
100 glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
101 glClear(GL_COLOR_BUFFER_BIT);
102
103 int maxSamples = 0;
104 glGetIntegerv(GL_MAX_SAMPLES, &maxSamples);
105
106 QByteArray extensions((const char *) glGetString(GL_EXTENSIONS));
107 frameInfo.msaaSupported = maxSamples > 0
108 && extensions.contains("GL_EXT_framebuffer_multisample")
109 && extensions.contains("GL_EXT_framebuffer_blit");
110
111 int samples;
112 glGetIntegerv(GL_SAMPLES, &samples);
113 frameInfo.msaaEnabled = samples > 0;
114
115 frameInfo.fboSize = framebufferObject()->size();
116
117 frameInfo.renderCount++;
118}
119
120void ColorRenderer::synchronize(QQuickFramebufferObject *item)
121{
122 FBOItem *fboItem = qobject_cast<FBOItem *>(item);
123 color = fboItem->color();
124 msaa = fboItem->msaa();
125 if (textureSize != fboItem->textureSize()) {
126 textureSize = fboItem->textureSize();
127 invalidateFramebufferObject();
128 }
129}
130
131QOpenGLFramebufferObject *ColorRenderer::createFramebufferObject(const QSize &size)
132{
133 initializeOpenGLFunctions();
134 frameInfo.createFBOCount++;
135 QOpenGLFramebufferObjectFormat format;
136 if (msaa)
137 format.setSamples(4);
138 QSize s = textureSize.isValid() ? textureSize : size;
139 return new QOpenGLFramebufferObject(s, format);
140}
141
142class tst_QQuickFramebufferObject: public QQmlDataTest
143{
144 Q_OBJECT
145public:
146private slots:
147 void testThatStuffWorks_data();
148 void testThatStuffWorks();
149
150 void testInvalidate();
151};
152
153void tst_QQuickFramebufferObject::testThatStuffWorks_data()
154{
155 QTest::addColumn<uint>("color");
156 QTest::addColumn<bool>("msaa");
157 QTest::addColumn<QSize>("textureSize");
158
159 QTest::newRow("red, !aa, item-size") << 0xffff0000 << false << QSize();
160 QTest::newRow("green, !aa, 80x80") << 0xff00ff00 << false << QSize(80, 80);
161 QTest::newRow("blue, aa, item-size") << 0xff0000ff << true << QSize();
162 QTest::newRow("pink, aa, 80x80") << 0xffff00ff << true << QSize(80, 80);
163}
164
165void tst_QQuickFramebufferObject::testThatStuffWorks()
166{
167 QFETCH(uint, color);
168 QFETCH(bool, msaa);
169 QFETCH(QSize, textureSize);
170
171#if defined(Q_OS_WIN32) && defined(QT_OPENGL_ES_2_ANGLE)
172 QSKIP("QTBUG-41815");
173#endif
174
175 frameInfo.renderCount = 0;
176 frameInfo.msaaEnabled = false;
177 frameInfo.msaaSupported = false;
178 frameInfo.fboSize = QSize();
179
180 qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem");
181
182 QQuickView view;
183 view.setSource(testFileUrl("testStuff.qml"));
184
185 FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo");
186
187 item->setColor(color);
188 if (textureSize.isValid()) {
189 item->setTextureFollowsItemSize(false);
190 item->setTextureSize(textureSize);
191 }
192 item->setMsaa(msaa);
193
194 view.show();
195 view.requestActivate();
196 QVERIFY(QTest::qWaitForWindowExposed(&view));
197
198 QImage result = view.grabWindow();
199
200 QCOMPARE(frameInfo.renderCount, 1);
201 QCOMPARE(result.pixel(0, 0), color);
202 if (textureSize.isValid())
203 QCOMPARE(frameInfo.fboSize, textureSize);
204 else
205 QCOMPARE(frameInfo.fboSize, QSize(item->width(), item->height()) * view.devicePixelRatio());
206 if (frameInfo.msaaSupported && msaa)
207 QVERIFY(frameInfo.msaaEnabled);
208
209 // Resize the item and grab again
210 item->setSize(QSize(200, 200));
211 result = view.grabWindow();
212
213 QCOMPARE(frameInfo.renderCount, 2);
214 QCOMPARE(result.pixel(150, 150), color);
215 if (textureSize.isValid())
216 QCOMPARE(frameInfo.fboSize, textureSize);
217 else
218 QCOMPARE(frameInfo.fboSize, QSize(item->width(), item->height()) * view.devicePixelRatio());
219 if (frameInfo.msaaSupported && msaa)
220 QVERIFY(frameInfo.msaaEnabled);
221}
222
223void tst_QQuickFramebufferObject::testInvalidate()
224{
225 qmlRegisterType<FBOItem>("FBOItem", 1, 0, "FBOItem");
226
227 QQuickView view;
228 view.setSource(testFileUrl("testStuff.qml"));
229
230 FBOItem *item = view.rootObject()->findChild<FBOItem *>("fbo");
231 item->setTextureFollowsItemSize(false);
232 item->setTextureSize(QSize(200, 200));
233
234 view.show();
235 view.requestActivate();
236 QVERIFY(QTest::qWaitForWindowExposed(&view));
237
238 QCOMPARE(frameInfo.fboSize, QSize(200, 200));
239
240 frameInfo.createFBOCount = 0;
241 item->setTextureSize(QSize(300, 300));
242 item->update();
243
244 QTRY_COMPARE(frameInfo.createFBOCount, 1);
245 QTRY_COMPARE(frameInfo.fboSize, QSize(300, 300));
246}
247
248QTEST_MAIN(tst_QQuickFramebufferObject)
249
250#include "tst_qquickframebufferobject.moc"
251