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 QtOpenGL 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#include <QtTest/QtTest>
30#include <QtOpenGL/qgl.h>
31#include <QtOpenGL/qglbuffer.h>
32
33class tst_QGLBuffer : public QObject
34{
35 Q_OBJECT
36public:
37 tst_QGLBuffer() {}
38 ~tst_QGLBuffer() {}
39
40private slots:
41 void vertexBuffer_data();
42 void vertexBuffer();
43 void indexBuffer_data();
44 void indexBuffer();
45 void bufferSharing();
46
47private:
48 void testBuffer(QGLBuffer::Type type);
49};
50
51void tst_QGLBuffer::vertexBuffer_data()
52{
53 QTest::addColumn<int>(name: "usagePattern");
54
55 QTest::newRow(dataTag: "StreamDraw") << int(QGLBuffer::StreamDraw);
56 QTest::newRow(dataTag: "StaticDraw") << int(QGLBuffer::StaticDraw);
57 QTest::newRow(dataTag: "DynamicDraw") << int(QGLBuffer::DynamicDraw);
58}
59
60void tst_QGLBuffer::vertexBuffer()
61{
62 testBuffer(type: QGLBuffer::VertexBuffer);
63}
64
65void tst_QGLBuffer::indexBuffer_data()
66{
67 vertexBuffer_data();
68}
69
70void tst_QGLBuffer::indexBuffer()
71{
72 testBuffer(type: QGLBuffer::IndexBuffer);
73}
74
75void tst_QGLBuffer::testBuffer(QGLBuffer::Type type)
76{
77 QFETCH(int, usagePattern);
78
79 QGLWidget w;
80 w.makeCurrent();
81
82 // Create the local object, but not the buffer in the server.
83 QGLBuffer buffer(type);
84 QCOMPARE(buffer.usagePattern(), QGLBuffer::StaticDraw);
85 buffer.setUsagePattern(QGLBuffer::UsagePattern(usagePattern));
86
87 // Check the initial state.
88 QCOMPARE(buffer.type(), type);
89 QVERIFY(!buffer.isCreated());
90 QCOMPARE(buffer.bufferId(), GLuint(0));
91 QCOMPARE(buffer.usagePattern(), QGLBuffer::UsagePattern(usagePattern));
92 QCOMPARE(buffer.size(), -1);
93
94 // Should not be able to bind it yet because it isn't created.
95 QVERIFY(!buffer.bind());
96
97 // Create the buffer - if this fails, then assume that the
98 // GL implementation does not support buffers at all.
99 if (!buffer.create())
100 QSKIP("Buffers are not supported on this platform");
101
102 // Should now have a buffer id.
103 QVERIFY(buffer.bufferId() != 0);
104
105 // Bind the buffer and upload some data.
106 QVERIFY(buffer.bind());
107 static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
108 buffer.allocate(data, count: sizeof(data));
109
110 // Check the buffer size.
111 QCOMPARE(buffer.size(), int(sizeof(data)));
112
113 // Map the buffer and read back its contents.
114 bool haveMap = false;
115 GLfloat *mapped = reinterpret_cast<GLfloat *>
116 (buffer.map(access: QGLBuffer::ReadOnly));
117 if (mapped) {
118 for (int index = 0; index < 9; ++index)
119 QCOMPARE(mapped[index], data[index]);
120 buffer.unmap();
121 haveMap = true;
122 } else {
123 qWarning(msg: "QGLBuffer::map() is not supported on this platform");
124 }
125
126 // Read back the buffer contents using read().
127 bool haveRead = false;
128 GLfloat readdata[9];
129 if (buffer.read(offset: 0, data: readdata, count: sizeof(readdata))) {
130 for (int index = 0; index < 9; ++index)
131 QCOMPARE(readdata[index], data[index]);
132 haveRead = true;
133 } else {
134 qWarning(msg: "QGLBuffer::read() is not supported on this platform");
135 }
136
137 // Write some different data to a specific location and check it.
138 static GLfloat const diffdata[] = {11, 12, 13};
139 buffer.write(offset: sizeof(GLfloat) * 3, data: diffdata, count: sizeof(diffdata));
140 if (haveMap) {
141 mapped = reinterpret_cast<GLfloat *>(buffer.map(access: QGLBuffer::ReadOnly));
142 QVERIFY(mapped != 0);
143 for (int index = 0; index < 9; ++index) {
144 if (index >= 3 && index <= 5)
145 QCOMPARE(mapped[index], diffdata[index - 3]);
146 else
147 QCOMPARE(mapped[index], data[index]);
148 }
149 buffer.unmap();
150 }
151 if (haveRead) {
152 QVERIFY(buffer.read(0, readdata, sizeof(readdata)));
153 for (int index = 0; index < 9; ++index) {
154 if (index >= 3 && index <= 5)
155 QCOMPARE(readdata[index], diffdata[index - 3]);
156 else
157 QCOMPARE(readdata[index], data[index]);
158 }
159 }
160
161 // Write to the buffer using the return value from map.
162 if (haveMap) {
163 mapped = reinterpret_cast<GLfloat *>(buffer.map(access: QGLBuffer::WriteOnly));
164 QVERIFY(mapped != 0);
165 mapped[6] = 14;
166 buffer.unmap();
167
168 mapped = reinterpret_cast<GLfloat *>(buffer.map(access: QGLBuffer::ReadOnly));
169 QVERIFY(mapped != 0);
170 static GLfloat const diff2data[] = {11, 12, 13, 14};
171 for (int index = 0; index < 9; ++index) {
172 if (index >= 3 && index <= 6)
173 QCOMPARE(mapped[index], diff2data[index - 3]);
174 else
175 QCOMPARE(mapped[index], data[index]);
176 }
177 buffer.unmap();
178 }
179
180 // Resize the buffer.
181 buffer.allocate(count: sizeof(GLfloat) * 20);
182 QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 20));
183 buffer.allocate(data: 0, count: sizeof(GLfloat) * 32);
184 QCOMPARE(buffer.size(), int(sizeof(GLfloat) * 32));
185
186 // Release the buffer.
187 buffer.release();
188}
189
190void tst_QGLBuffer::bufferSharing()
191{
192#if defined(Q_OS_WIN)
193 // Needs investigation on Windows: QTBUG-29692
194 QSKIP("Unreproducible timeout on Windows (MSVC/MinGW) CI bots");
195#endif
196
197#if defined(Q_OS_QNX)
198 QSKIP("Crashes on QNX when destroying the second QGLWidget (see QTBUG-38275)");
199#endif
200
201 QGLWidget *w1 = new QGLWidget();
202 w1->makeCurrent();
203
204 QGLWidget *w2 = new QGLWidget(0, w1);
205 if (!w2->isSharing()) {
206 delete w2;
207 delete w1;
208 QSKIP("Context sharing is not supported on this platform");
209 }
210
211 // Bind the buffer in the first context and write some data to it.
212 QGLBuffer buffer(QGLBuffer::VertexBuffer);
213 if (!buffer.create())
214 QSKIP("Buffers are not supported on this platform");
215 QVERIFY(buffer.isCreated());
216 QVERIFY(buffer.bind());
217 static GLfloat const data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
218 buffer.allocate(data, count: sizeof(data));
219 QCOMPARE(buffer.size(), int(sizeof(data)));
220 buffer.release();
221
222 // Bind the buffer in the second context and read back the data.
223 w2->makeCurrent();
224 QVERIFY(buffer.bind());
225 QCOMPARE(buffer.size(), int(sizeof(data)));
226 GLfloat readdata[9];
227 if (buffer.read(offset: 0, data: readdata, count: sizeof(readdata))) {
228 for (int index = 0; index < 9; ++index)
229 QCOMPARE(readdata[index], data[index]);
230 }
231 buffer.release();
232
233 // Delete the first context.
234 delete w1;
235
236 // Make the second context current again because deleting the first
237 // one will call doneCurrent() even though it wasn't current!
238 w2->makeCurrent();
239
240 // The buffer should still be valid in the second context.
241 QVERIFY(buffer.bufferId() != 0);
242 QVERIFY(buffer.isCreated());
243 QVERIFY(buffer.bind());
244 QCOMPARE(buffer.size(), int(sizeof(data)));
245 buffer.release();
246
247 // Delete the second context.
248 delete w2;
249
250 // The buffer should now be invalid.
251 QCOMPARE(buffer.bufferId(), GLuint(0));
252 QVERIFY(!buffer.isCreated());
253}
254
255QTEST_MAIN(tst_QGLBuffer)
256
257#include "tst_qglbuffer.moc"
258

source code of qtbase/tests/auto/opengl/qglbuffer/tst_qglbuffer.cpp