1/****************************************************************************
2**
3** Copyright (C) 2019 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 <QtTest/QtTest>
30#include <QThread>
31#include <QFile>
32#include <QOffscreenSurface>
33#include <QtGui/private/qrhi_p.h>
34#include <QtGui/private/qrhinull_p.h>
35
36#if QT_CONFIG(opengl)
37# include <QtGui/private/qrhigles2_p.h>
38# define TST_GL
39#endif
40
41#if QT_CONFIG(vulkan)
42# include <QVulkanInstance>
43# include <QtGui/private/qrhivulkan_p.h>
44# define TST_VK
45#endif
46
47#ifdef Q_OS_WIN
48#include <QtGui/private/qrhid3d11_p.h>
49# define TST_D3D11
50#endif
51
52#ifdef Q_OS_DARWIN
53# include <QtGui/private/qrhimetal_p.h>
54# define TST_MTL
55#endif
56
57Q_DECLARE_METATYPE(QRhi::Implementation)
58Q_DECLARE_METATYPE(QRhiInitParams *)
59
60class tst_QRhi : public QObject
61{
62 Q_OBJECT
63
64private slots:
65 void initTestCase();
66 void cleanupTestCase();
67
68 void create_data();
69 void create();
70
71private:
72 struct {
73 QRhiNullInitParams null;
74#ifdef TST_GL
75 QRhiGles2InitParams gl;
76#endif
77#ifdef TST_VK
78 QRhiVulkanInitParams vk;
79#endif
80#ifdef TST_D3D11
81 QRhiD3D11InitParams d3d;
82#endif
83#ifdef TST_MTL
84 QRhiMetalInitParams mtl;
85#endif
86 } initParams;
87
88#ifdef TST_VK
89 QVulkanInstance vulkanInstance;
90#endif
91 QOffscreenSurface *fallbackSurface = nullptr;
92};
93
94void tst_QRhi::initTestCase()
95{
96#ifdef TST_GL
97 fallbackSurface = QRhiGles2InitParams::newFallbackSurface();
98 initParams.gl.fallbackSurface = fallbackSurface;
99#endif
100
101#ifdef TST_VK
102 vulkanInstance.create();
103 initParams.vk.inst = &vulkanInstance;
104#endif
105}
106
107void tst_QRhi::cleanupTestCase()
108{
109#ifdef TST_VK
110 vulkanInstance.destroy();
111#endif
112
113 delete fallbackSurface;
114}
115
116void tst_QRhi::create_data()
117{
118 QTest::addColumn<QRhi::Implementation>("impl");
119 QTest::addColumn<QRhiInitParams *>("initParams");
120
121 QTest::newRow("Null") << QRhi::Null << static_cast<QRhiInitParams *>(&initParams.null);
122#ifdef TST_GL
123 QTest::newRow("OpenGL") << QRhi::OpenGLES2 << static_cast<QRhiInitParams *>(&initParams.gl);
124#endif
125#ifdef TST_VK
126 if (vulkanInstance.isValid())
127 QTest::newRow("Vulkan") << QRhi::Vulkan << static_cast<QRhiInitParams *>(&initParams.vk);
128#endif
129#ifdef TST_D3D11
130 QTest::newRow("Direct3D 11") << QRhi::D3D11 << static_cast<QRhiInitParams *>(&initParams.d3d);
131#endif
132#ifdef TST_MTL
133 QTest::newRow("Metal") << QRhi::Metal << static_cast<QRhiInitParams *>(&initParams.mtl);
134#endif
135}
136
137static int aligned(int v, int a)
138{
139 return (v + a - 1) & ~(a - 1);
140}
141
142void tst_QRhi::create()
143{
144 // Merely attempting to create a QRhi should survive, with an error when
145 // not supported. (of course, there is always a chance we encounter a crash
146 // due to some random graphics stack...)
147
148 QFETCH(QRhi::Implementation, impl);
149 QFETCH(QRhiInitParams *, initParams);
150
151 QScopedPointer<QRhi> rhi(QRhi::create(impl, initParams, QRhi::Flags(), nullptr));
152
153 if (rhi) {
154 QCOMPARE(rhi->backend(), impl);
155 QCOMPARE(rhi->thread(), QThread::currentThread());
156
157 int cleanupOk = 0;
158 QRhi *rhiPtr = rhi.data();
159 auto cleanupFunc = [rhiPtr, &cleanupOk](QRhi *dyingRhi) {
160 if (rhiPtr == dyingRhi)
161 cleanupOk += 1;
162 };
163 rhi->addCleanupCallback(cleanupFunc);
164 rhi->runCleanup();
165 QCOMPARE(cleanupOk, 1);
166 cleanupOk = 0;
167 rhi->addCleanupCallback(cleanupFunc);
168
169 QRhiResourceUpdateBatch *resUpd = rhi->nextResourceUpdateBatch();
170 QVERIFY(resUpd);
171 resUpd->release();
172
173 QVERIFY(!rhi->supportedSampleCounts().isEmpty());
174 QVERIFY(rhi->supportedSampleCounts().contains(1));
175
176 QVERIFY(rhi->ubufAlignment() > 0);
177 QCOMPARE(rhi->ubufAligned(123), aligned(123, rhi->ubufAlignment()));
178
179 QCOMPARE(rhi->mipLevelsForSize(QSize(512, 300)), 10);
180 QCOMPARE(rhi->sizeForMipLevel(0, QSize(512, 300)), QSize(512, 300));
181 QCOMPARE(rhi->sizeForMipLevel(1, QSize(512, 300)), QSize(256, 150));
182 QCOMPARE(rhi->sizeForMipLevel(2, QSize(512, 300)), QSize(128, 75));
183 QCOMPARE(rhi->sizeForMipLevel(9, QSize(512, 300)), QSize(1, 1));
184
185 const bool fbUp = rhi->isYUpInFramebuffer();
186 const bool ndcUp = rhi->isYUpInNDC();
187 const bool d0to1 = rhi->isClipDepthZeroToOne();
188 const QMatrix4x4 corrMat = rhi->clipSpaceCorrMatrix();
189 if (impl == QRhi::OpenGLES2) {
190 QVERIFY(fbUp);
191 QVERIFY(ndcUp);
192 QVERIFY(!d0to1);
193 QVERIFY(corrMat.isIdentity());
194 } else if (impl == QRhi::Vulkan) {
195 QVERIFY(!fbUp);
196 QVERIFY(!ndcUp);
197 QVERIFY(d0to1);
198 QVERIFY(!corrMat.isIdentity());
199 } else if (impl == QRhi::D3D11) {
200 QVERIFY(!fbUp);
201 QVERIFY(ndcUp);
202 QVERIFY(d0to1);
203 QVERIFY(!corrMat.isIdentity());
204 } else if (impl == QRhi::Metal) {
205 QVERIFY(!fbUp);
206 QVERIFY(ndcUp);
207 QVERIFY(d0to1);
208 QVERIFY(!corrMat.isIdentity());
209 }
210
211 const int texMin = rhi->resourceLimit(QRhi::TextureSizeMin);
212 const int texMax = rhi->resourceLimit(QRhi::TextureSizeMax);
213 const int maxAtt = rhi->resourceLimit(QRhi::MaxColorAttachments);
214 QVERIFY(texMin >= 1);
215 QVERIFY(texMax >= texMin);
216 QVERIFY(maxAtt >= 1);
217
218 QVERIFY(rhi->nativeHandles());
219 QVERIFY(rhi->profiler());
220
221 const QRhi::Feature features[] = {
222 QRhi::MultisampleTexture,
223 QRhi::MultisampleRenderBuffer,
224 QRhi::DebugMarkers,
225 QRhi::Timestamps,
226 QRhi::Instancing,
227 QRhi::CustomInstanceStepRate,
228 QRhi::PrimitiveRestart,
229 QRhi::NonDynamicUniformBuffers,
230 QRhi::NonFourAlignedEffectiveIndexBufferOffset,
231 QRhi::NPOTTextureRepeat,
232 QRhi::RedOrAlpha8IsRed,
233 QRhi::ElementIndexUint
234 };
235 for (size_t i = 0; i <sizeof(features) / sizeof(QRhi::Feature); ++i)
236 rhi->isFeatureSupported(features[i]);
237
238 QVERIFY(rhi->isTextureFormatSupported(QRhiTexture::RGBA8));
239
240 rhi.reset();
241 QCOMPARE(cleanupOk, 1);
242 }
243}
244
245#include <tst_qrhi.moc>
246QTEST_MAIN(tst_QRhi)
247