1/****************************************************************************
2**
3** Copyright (C) 2016 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#include <QtTest/QTest>
30#include <Qt3DRender/qrendertargetoutput.h>
31#include <Qt3DRender/private/uniform_p.h>
32#include <graphicshelpergl2_p.h>
33#include <Qt3DRender/private/attachmentpack_p.h>
34#include <QtOpenGLExtensions/QOpenGLExtensions>
35#include <QOpenGLContext>
36#include <QOpenGLBuffer>
37#include <QOpenGLFunctions_2_0>
38#include <QOpenGLShaderProgram>
39#include <QOpenGLVertexArrayObject>
40#include <QSurfaceFormat>
41
42#ifndef QT_OPENGL_ES_2
43
44#define TEST_SHOULD_BE_PERFORMED 1
45
46QT_BEGIN_NAMESPACE
47
48using namespace Qt3DRender;
49using namespace Qt3DRender::Render;
50using namespace Qt3DRender::Render::OpenGL;
51
52namespace {
53
54const QByteArray vertCode = QByteArrayLiteral(
55 "#version 120\n" \
56 "attribute vec3 vertexPosition;\n" \
57 "attribute vec2 vertexTexCoord;\n" \
58 "varying vec2 texCoord;\n" \
59 "void main()\n" \
60 "{\n" \
61 " texCoord = vertexTexCoord;\n" \
62 " gl_Position = vec4(vertexPosition, 1.0);\n" \
63 "}\n");
64
65const QByteArray fragCodeUniformsFloat = QByteArrayLiteral(
66 "#version 120\n" \
67 "uniform float multiplier;\n" \
68 "uniform vec2 multiplierVec2;\n" \
69 "uniform vec3 multiplierVec3;\n" \
70 "uniform vec4 multiplierVec4;\n" \
71 "void main()\n" \
72 "{\n" \
73 " vec4 randomMult = multiplierVec4 + vec4(multiplierVec3, 0.0) + vec4(multiplierVec2, 0.0, 0.0);\n" \
74 " gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0) * randomMult * multiplier;\n" \
75 "}\n");
76
77const QByteArray fragCodeUniformsInt = QByteArrayLiteral(
78 "#version 120\n" \
79 "uniform int multiplier;\n" \
80 "uniform ivec2 multiplierVec2;\n" \
81 "uniform ivec3 multiplierVec3;\n" \
82 "uniform ivec4 multiplierVec4;\n" \
83 "void main()\n" \
84 "{\n" \
85 " ivec4 randomMult = multiplierVec4 + ivec4(multiplierVec3, 0) + ivec4(multiplierVec2, 0, 0);\n" \
86 " gl_FragColor = ivec4(1, 0, 0, 1) * randomMult * multiplier;\n" \
87 "}\n");
88
89const QByteArray fragCodeUniformsFloatMatrices = QByteArrayLiteral(
90 "#version 120\n" \
91 "uniform mat2 m2;\n" \
92 "uniform mat2x3 m23;\n" \
93 "uniform mat3x2 m32;\n" \
94 "uniform mat2x4 m24;\n" \
95 "uniform mat4x2 m42;\n" \
96 "uniform mat3 m3;\n" \
97 "uniform mat3x4 m34;\n" \
98 "uniform mat4x3 m43;\n" \
99 "uniform mat4 m4;\n" \
100 "void main()\n" \
101 "{\n" \
102 " float lengthSum = m2[0][0] + m23[0][0] + m32[0][0] + m24[0][0] + m42[0][0] + m3[0][0] + m34[0][0] + m43[0][0] + m4[0][0];\n" \
103 " gl_FragColor = vec4(1, 0, 0, 1) * lengthSum;\n" \
104 "}\n");
105
106
107const QByteArray fragCodeSamplers = QByteArrayLiteral(
108 "#version 120\n" \
109 "varying vec2 texCoord;\n" \
110 "uniform sampler1D s1;\n" \
111 "uniform sampler2D s2;\n" \
112 "uniform sampler3D s3;\n" \
113 "uniform samplerCube scube;\n" \
114 "void main()\n" \
115 "{\n" \
116 " gl_FragColor = vec4(1, 0, 0, 1) *" \
117 " texture1D(s1, texCoord.x) *" \
118 " texture2D(s2, texCoord) *" \
119 " texture3D(s3, vec3(texCoord, 0.0)) *" \
120 " textureCube(scube, vec3(texCoord, 0));\n" \
121 "}\n");
122
123} // anonymous
124
125class tst_GraphicsHelperGL2 : public QObject
126{
127 Q_OBJECT
128private Q_SLOTS:
129
130 void init()
131 {
132 m_window.reset(other: new QWindow);
133 m_window->setSurfaceType(QWindow::OpenGLSurface);
134 m_window->setGeometry(posx: 0, posy: 0, w: 10, h: 10);
135 m_window->create();
136
137 QSurfaceFormat format;
138 format.setVersion(major: 2, minor: 0);
139 format.setProfile(QSurfaceFormat::NoProfile);
140 format.setDepthBufferSize(24);
141 format.setSamples(4);
142 format.setStencilBufferSize(8);
143 m_window->setFormat(format);
144 m_glContext.setFormat(format);
145
146 if (!m_glContext.create()) {
147 qWarning() << "Failed to create OpenGL context";
148 return;
149 }
150
151 if (!m_glContext.makeCurrent(surface: m_window.data())) {
152 qWarning() << "Failed to make OpenGL context current";
153 return;
154 }
155
156 if ((m_func = m_glContext.versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) {
157 if (m_glContext.hasExtension(QByteArrayLiteral("GL_ARB_framebuffer_object"))) {
158 m_fboFuncs = new QOpenGLExtension_ARB_framebuffer_object();
159 m_fboFuncs->initializeOpenGLFunctions();
160 }
161 m_glHelper.initializeHelper(context: &m_glContext, functions: m_func);
162 m_initializationSuccessful = true;
163 }
164 }
165
166 void cleanup()
167 {
168 m_glContext.doneCurrent();
169 }
170
171 void alphaTest()
172 {
173 if (!m_initializationSuccessful)
174 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
175 // Deprecated
176 }
177
178 void bindBufferBase()
179 {
180 if (!m_initializationSuccessful)
181 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
182
183 // Not supported by GL2
184 }
185
186 void bindFragDataLocation()
187 {
188 if (!m_initializationSuccessful)
189 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
190 // Not supported by GL2
191 }
192
193 void bindFrameBufferAttachment()
194 {
195 if (!m_initializationSuccessful)
196 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
197
198 if (!m_fboFuncs)
199 QSKIP("FBO not supported by OpenGL 2.0");
200
201 // GIVEN
202 GLuint fboId;
203 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
204
205 Attachment attachment;
206 attachment.m_point = QRenderTargetOutput::Color0;
207
208 // THEN
209 QVERIFY(fboId != 0);
210
211 // WHEN
212 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: fboId);
213
214 QOpenGLTexture texture(QOpenGLTexture::Target2D);
215 texture.setSize(width: 512, height: 512);
216 texture.setFormat(QOpenGLTexture::RGBA32F);
217 texture.setMinificationFilter(QOpenGLTexture::Linear);
218 texture.setMagnificationFilter(QOpenGLTexture::Linear);
219 texture.setWrapMode(QOpenGLTexture::ClampToEdge);
220 if (!texture.create())
221 qWarning() << "Texture creation failed";
222 texture.allocateStorage();
223 QVERIFY(texture.isStorageAllocated());
224 GLint error = m_func->glGetError();
225 QVERIFY(error == 0);
226 m_glHelper.bindFrameBufferAttachment(texture: &texture, attachment);
227
228 // THEN
229 GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
230 QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
231
232 error = m_func->glGetError();
233 QVERIFY(error == 0);
234 GLint textureAttachmentId = 0;
235 m_fboFuncs->glGetFramebufferAttachmentParameteriv(GL_DRAW_FRAMEBUFFER,
236 GL_COLOR_ATTACHMENT0,
237 GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
238 params: &textureAttachmentId);
239 QCOMPARE(GLuint(textureAttachmentId), texture.textureId());
240
241 // Restore state
242 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: 0);
243 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
244 }
245
246 void bindFrameBufferObject()
247 {
248 if (!m_initializationSuccessful)
249 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
250 if (!m_fboFuncs)
251 QSKIP("FBO not supported by OpenGL 2.0");
252
253 // GIVEN
254 GLuint fboId;
255 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
256
257 // THEN
258 QVERIFY(fboId != 0);
259
260 // WHEN
261 m_glHelper.bindFrameBufferObject(frameBufferId: fboId, mode: GraphicsHelperInterface::FBODraw);
262
263 // THEN
264 GLint error = m_func->glGetError();
265 QVERIFY(error == 0);
266 GLint boundindFBOId = 0;
267 m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, params: &boundindFBOId);
268 QVERIFY(GLuint(boundindFBOId) == fboId);
269
270 // WHEN
271 m_glHelper.bindFrameBufferObject(frameBufferId: fboId, mode: GraphicsHelperInterface::FBORead);
272
273 // THEN
274 error = m_func->glGetError();
275 QVERIFY(error == 0);
276 boundindFBOId = 0;
277 m_func->glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, params: &boundindFBOId);
278 QVERIFY(GLuint(boundindFBOId) == fboId);
279
280 // WHEN
281 m_glHelper.bindFrameBufferObject(frameBufferId: fboId, mode: GraphicsHelperInterface::FBOReadAndDraw);
282
283 // THEN
284 error = m_func->glGetError();
285 QVERIFY(error == 0);
286 boundindFBOId = 0;
287 m_func->glGetIntegerv(GL_FRAMEBUFFER_BINDING, params: &boundindFBOId);
288 QVERIFY(GLuint(boundindFBOId) == fboId);
289
290 // Cleanup
291 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
292 }
293
294 void bindShaderStorageBlock()
295 {
296 if (!m_initializationSuccessful)
297 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
298 // Not supported by GL2
299 }
300
301 void bindUniformBlock()
302 {
303 if (!m_initializationSuccessful)
304 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
305 // Not supported by GL2
306 }
307
308 void blendEquation()
309 {
310 if (!m_initializationSuccessful)
311 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
312
313 // GIVEN
314 GLint equation = 0;
315 m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, params: &equation);
316 QCOMPARE(equation, GL_FUNC_ADD);
317
318 // WHEN
319 m_glHelper.blendEquation(GL_FUNC_REVERSE_SUBTRACT);
320
321 // THEN
322 m_func->glGetIntegerv(GL_BLEND_EQUATION_RGB, params: &equation);
323 QCOMPARE(equation, GL_FUNC_REVERSE_SUBTRACT);
324 }
325
326 void blendFunci()
327 {
328 if (!m_initializationSuccessful)
329 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
330 // Not supported by GL2
331 }
332
333 void blendFuncSeparatei()
334 {
335 if (!m_initializationSuccessful)
336 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
337 // Not supported by GL2
338 }
339
340 void boundFrameBufferObject()
341 {
342 if (!m_initializationSuccessful)
343 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
344 if (!m_fboFuncs)
345 QSKIP("FBO not supported by OpenGL 2.0");
346
347 // GIVEN
348 GLuint fboId;
349 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
350
351 // WHEN
352 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: fboId);
353
354 // THEN
355 GLint boundBuffer = 0;
356 m_func->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, params: &boundBuffer);
357 QCOMPARE(GLuint(boundBuffer), fboId);
358
359 // THEN
360 QCOMPARE(m_glHelper.boundFrameBufferObject(), fboId);
361
362 // Reset state
363 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: 0);
364 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
365 }
366
367 void checkFrameBufferComplete()
368 {
369 if (!m_initializationSuccessful)
370 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
371 if (!m_fboFuncs)
372 QSKIP("FBO not supported by OpenGL 2.0");
373
374 // GIVEN
375 GLuint fboId;
376 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
377
378 Attachment attachment;
379 attachment.m_point = QRenderTargetOutput::Color0;
380
381 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: fboId);
382
383 QOpenGLTexture texture(QOpenGLTexture::Target2D);
384 texture.setSize(width: 512, height: 512);
385 texture.setFormat(QOpenGLTexture::RGBA8U);
386 texture.setMinificationFilter(QOpenGLTexture::Linear);
387 texture.setMagnificationFilter(QOpenGLTexture::Linear);
388 texture.create();
389 texture.allocateStorage();
390 m_glHelper.bindFrameBufferAttachment(texture: &texture, attachment);
391
392 // THEN
393 GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
394 QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
395
396 QVERIFY(m_glHelper.checkFrameBufferComplete());
397
398 // Restore
399 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: 0);
400 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
401 }
402
403 void clearBufferf()
404 {
405 if (!m_initializationSuccessful)
406 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
407 // Not supported by GL2
408 }
409
410 void createFrameBufferObject()
411 {
412 if (!m_initializationSuccessful)
413 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
414 if (!m_fboFuncs)
415 QSKIP("FBO not supported by OpenGL 2.0");
416
417 // WHEN
418 const GLuint fboId = m_glHelper.createFrameBufferObject();
419
420 // THEN
421 QVERIFY(fboId != 0);
422
423 // Restore
424 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
425 }
426
427 void depthMask()
428 {
429 if (!m_initializationSuccessful)
430 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
431
432 // GIVEN
433 GLboolean depthWritingEnabled = false;
434 m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, params: &depthWritingEnabled);
435
436 // THEN
437 QVERIFY(depthWritingEnabled);
438
439 // WHEN
440 m_glHelper.depthMask(GL_FALSE);
441
442 // THEN
443 m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, params: &depthWritingEnabled);
444 QVERIFY(!depthWritingEnabled);
445
446 // WHEN
447 m_glHelper.depthMask(GL_TRUE);
448
449 // THEN
450 m_func->glGetBooleanv(GL_DEPTH_WRITEMASK, params: &depthWritingEnabled);
451 QVERIFY(depthWritingEnabled);
452 }
453
454 void depthTest()
455 {
456 if (!m_initializationSuccessful)
457 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
458
459 // GIVEN
460 m_func->glDisable(GL_DEPTH_TEST);
461 m_func->glDepthFunc(GL_LESS);
462
463 // WHEN
464 m_glHelper.depthTest(GL_LEQUAL);
465
466 // THEN
467 QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
468 GLint depthMode = 0;
469 m_func->glGetIntegerv(GL_DEPTH_FUNC, params: &depthMode);
470 QCOMPARE(depthMode, GL_LEQUAL);
471
472 // WHEN
473 m_glHelper.depthTest(GL_LESS);
474 QVERIFY(m_func->glIsEnabled(GL_DEPTH_TEST));
475 m_func->glGetIntegerv(GL_DEPTH_FUNC, params: &depthMode);
476 QCOMPARE(depthMode, GL_LESS);
477 }
478
479 void disableClipPlane()
480 {
481 if (!m_initializationSuccessful)
482 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
483
484 // GIVEN
485 m_func->glEnable(GL_CLIP_DISTANCE0 + 5);
486
487 // THEN
488 QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
489
490 // WHEN
491 m_glHelper.disableClipPlane(clipPlane: 5);
492
493 // THEN
494 QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 5));
495 }
496
497 void disablei()
498 {
499 if (!m_initializationSuccessful)
500 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
501 // Not supported by GL2
502 }
503
504 void disablePrimitiveRestart()
505 {
506 if (!m_initializationSuccessful)
507 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
508 // Not supported by GL2
509 }
510
511 void drawBuffers()
512 {
513 if (!m_initializationSuccessful)
514 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
515
516 if (!m_fboFuncs)
517 QSKIP("FBO not supported by OpenGL 2.0");
518
519 // GIVEN
520 GLuint fboId;
521 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
522
523 // THEN
524 QVERIFY(fboId != 0);
525
526 // WHEN
527 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: fboId);
528 QOpenGLTexture *textures[4];
529
530 // Create 4 attachments
531 for (int i = 0; i < 4; ++i) {
532 Attachment attachment;
533 attachment.m_point = static_cast<QRenderTargetOutput::AttachmentPoint>(i);
534
535 QOpenGLTexture *texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
536 textures[i] = texture;
537 texture->setSize(width: 512, height: 512);
538 texture->setFormat(QOpenGLTexture::RGBA32F);
539 texture->setMinificationFilter(QOpenGLTexture::Linear);
540 texture->setMagnificationFilter(QOpenGLTexture::Linear);
541 texture->setWrapMode(QOpenGLTexture::ClampToEdge);
542 if (!texture->create())
543 qWarning() << "Texture creation failed";
544 texture->allocateStorage();
545 QVERIFY(texture->isStorageAllocated());
546 GLint error = m_func->glGetError();
547 QVERIFY(error == 0);
548 m_glHelper.bindFrameBufferAttachment(texture, attachment);
549 }
550 // THEN
551 GLenum status = m_fboFuncs->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
552 QVERIFY(status == GL_FRAMEBUFFER_COMPLETE);
553
554 // WHEN
555 GLenum bufferEnum = GL_COLOR_ATTACHMENT4;
556 m_func->glDrawBuffers(n: 1, bufs: &bufferEnum);
557
558 // THEN
559 GLint enumValue = -1;
560 m_func->glGetIntegerv(GL_DRAW_BUFFER0, params: &enumValue);
561 QCOMPARE(enumValue, GL_COLOR_ATTACHMENT4);
562
563 // WHEN
564 GLint newBufferEnum = 2;
565 m_glHelper.drawBuffers(n: 1, bufs: &newBufferEnum);
566
567 // THEN
568 m_func->glGetIntegerv(GL_DRAW_BUFFER0, params: &enumValue);
569 QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
570
571 // WHEN
572 newBufferEnum = 0;
573 m_glHelper.drawBuffers(n: 1, bufs: &newBufferEnum);
574
575 // THEN
576 m_func->glGetIntegerv(GL_DRAW_BUFFER0, params: &enumValue);
577 QCOMPARE(enumValue, GL_COLOR_ATTACHMENT0 + newBufferEnum);
578
579 // Restore
580 m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, framebuffer: 0);
581 m_fboFuncs->glDeleteFramebuffers(n: 1, framebuffers: &fboId);
582 for (int i = 0; i < 4; ++i)
583 delete textures[i];
584 }
585
586 void enableClipPlane()
587 {
588 if (!m_initializationSuccessful)
589 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
590
591 // GIVEN
592 m_func->glDisable(GL_CLIP_DISTANCE0 + 4);
593
594 // THEN
595 QVERIFY(!m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
596
597 // WHEN
598 m_glHelper.enableClipPlane(clipPlane: 4);
599
600 // THEN
601 QVERIFY(m_func->glIsEnabled(GL_CLIP_DISTANCE0 + 4));
602 }
603
604 void enablei()
605 {
606 if (!m_initializationSuccessful)
607 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
608 // Not supported by GL2
609 }
610
611 void enablePrimitiveRestart()
612 {
613 if (!m_initializationSuccessful)
614 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
615 // Not supported by GL2
616 }
617
618 void enableVertexAttribute()
619 {
620 if (!m_initializationSuccessful)
621 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
622
623 // GIVEN
624 QOpenGLVertexArrayObject vao;
625 vao.create();
626 QOpenGLVertexArrayObject::Binder binder(&vao);
627
628 QOpenGLShaderProgram shaderProgram;
629 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
630 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeSamplers);
631 QVERIFY(shaderProgram.link());
632 shaderProgram.bind();
633
634 // WHEN
635 GLint positionLocation = m_func->glGetAttribLocation(program: shaderProgram.programId(), name: "vertexPosition");
636 GLint texCoordLocation = m_func->glGetAttribLocation(program: shaderProgram.programId(), name: "vertexTexCoord");
637 m_glHelper.enableVertexAttributeArray(location: positionLocation);
638 m_glHelper.enableVertexAttributeArray(location: texCoordLocation);
639
640 // THEN
641 const GLint error = m_func->glGetError();
642 QVERIFY(error == 0);
643 }
644
645 void frontFace()
646 {
647 if (!m_initializationSuccessful)
648 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
649
650 // GIVEN
651 m_func->glFrontFace(GL_CW);
652
653 // THEN
654 GLint face = 0;
655 m_func->glGetIntegerv(GL_FRONT_FACE, params: &face);
656 QCOMPARE(face, GL_CW);
657
658 // WHEN
659 m_glHelper.frontFace(GL_CCW);
660
661 // THEN
662 m_func->glGetIntegerv(GL_FRONT_FACE, params: &face);
663 QCOMPARE(face, GL_CCW);
664 }
665
666 void getRenderBufferDimensions()
667 {
668 if (!m_initializationSuccessful)
669 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
670 // Not supported by GL2
671 }
672
673 void getTextureDimensions()
674 {
675 if (!m_initializationSuccessful)
676 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
677
678 // GIVEN
679 QOpenGLTexture texture(QOpenGLTexture::Target2D);
680 texture.setSize(width: 512, height: 512);
681 texture.setFormat(QOpenGLTexture::RGBA8U);
682 texture.setMinificationFilter(QOpenGLTexture::Linear);
683 texture.setMagnificationFilter(QOpenGLTexture::Linear);
684 texture.create();
685 texture.allocateStorage();
686
687 // WHEN
688 const QSize dimensions = m_glHelper.getTextureDimensions(textureId: texture.textureId(), GL_TEXTURE_2D);
689
690 // THEN
691 QCOMPARE(dimensions, QSize(512, 512));
692 }
693
694 void pointSize()
695 {
696 if (!m_initializationSuccessful)
697 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
698
699 // WHEN
700 m_glHelper.pointSize(programmable: false, value: 0.5f);
701 // THEN
702 GLfloat size = 0.0f;
703 m_func->glGetFloatv(GL_POINT_SIZE, params: &size);
704 QCOMPARE(size, 0.5f);
705 }
706
707 void maxClipPlaneCount()
708 {
709 if (!m_initializationSuccessful)
710 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
711
712 // GIVEN
713 GLint maxCount = -1;
714 m_func->glGetIntegerv(GL_MAX_CLIP_PLANES, params: &maxCount);
715
716 // THEN
717 QCOMPARE(maxCount, m_glHelper.maxClipPlaneCount());
718 }
719
720 void programUniformBlock()
721 {
722 if (!m_initializationSuccessful)
723 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
724
725 // Not supported by GL2
726 }
727
728 void programAttributesAndLocations()
729 {
730 if (!m_initializationSuccessful)
731 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
732
733 // GIVEN
734 QOpenGLShaderProgram shaderProgram;
735 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
736 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeSamplers);
737 QVERIFY(shaderProgram.link());
738
739 // WHEN
740 QVector<ShaderAttribute> activeAttributes = m_glHelper.programAttributesAndLocations(programId: shaderProgram.programId());
741
742 // THEN
743 QCOMPARE(activeAttributes.size(), 2);
744 std::sort(first: activeAttributes.begin(), last: activeAttributes.end(), comp: [] (const ShaderAttribute &a, const ShaderAttribute &b) { return a.m_name < b.m_name; });
745
746 const ShaderAttribute attribute1 = activeAttributes.at(i: 0);
747 QCOMPARE(attribute1.m_name, QStringLiteral("vertexPosition"));
748 QCOMPARE(attribute1.m_size, 1);
749 QCOMPARE(attribute1.m_location, shaderProgram.attributeLocation("vertexPosition"));
750 QCOMPARE(attribute1.m_type, GLenum(GL_FLOAT_VEC3));
751
752 const ShaderAttribute attribute2 = activeAttributes.at(i: 1);
753 QCOMPARE(attribute2.m_name, QStringLiteral("vertexTexCoord"));
754 QCOMPARE(attribute2.m_size, 1);
755 QCOMPARE(attribute2.m_location, shaderProgram.attributeLocation("vertexTexCoord"));
756 QCOMPARE(attribute2.m_type, GLenum(GL_FLOAT_VEC2));
757 }
758
759 void programUniformsAndLocations()
760 {
761 if (!m_initializationSuccessful)
762 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
763
764 // GIVEN
765 QOpenGLShaderProgram shaderProgram;
766 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
767 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
768 QVERIFY(shaderProgram.link());
769
770 // WHEN
771 QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(programId: shaderProgram.programId());
772
773 // THEN
774 QCOMPARE(activeUniforms.size(), 4);
775 std::sort(first: activeUniforms.begin(), last: activeUniforms.end(), comp: [] (const ShaderUniform &a, const ShaderUniform &b) { return a.m_name < b.m_name; });
776
777 const ShaderUniform uniform1 = activeUniforms.at(i: 0);
778 QCOMPARE(uniform1.m_location, shaderProgram.uniformLocation("multiplier"));
779 QCOMPARE(uniform1.m_offset, -1);
780 QCOMPARE(uniform1.m_blockIndex, -1);
781 QCOMPARE(uniform1.m_arrayStride, -1);
782 QCOMPARE(uniform1.m_matrixStride, -1);
783 QCOMPARE(uniform1.m_size, 1);
784 QCOMPARE(uniform1.m_type, GLenum(GL_FLOAT));
785 QCOMPARE(uniform1.m_name, QStringLiteral("multiplier"));
786
787 const ShaderUniform uniform2 = activeUniforms.at(i: 1);
788 QCOMPARE(uniform2.m_location, shaderProgram.uniformLocation("multiplierVec2"));
789 QCOMPARE(uniform2.m_offset, -1);
790 QCOMPARE(uniform2.m_blockIndex, -1);
791 QCOMPARE(uniform2.m_arrayStride, -1);
792 QCOMPARE(uniform2.m_matrixStride, -1);
793 QCOMPARE(uniform2.m_size, 1);
794 QCOMPARE(uniform2.m_type, GLenum(GL_FLOAT_VEC2));
795 QCOMPARE(uniform2.m_name, QStringLiteral("multiplierVec2"));
796
797 const ShaderUniform uniform3 = activeUniforms.at(i: 2);
798 QCOMPARE(uniform3.m_location, shaderProgram.uniformLocation("multiplierVec3"));
799 QCOMPARE(uniform3.m_offset, -1);
800 QCOMPARE(uniform3.m_blockIndex, -1);
801 QCOMPARE(uniform3.m_arrayStride, -1);
802 QCOMPARE(uniform3.m_matrixStride, -1);
803 QCOMPARE(uniform3.m_size, 1);
804 QCOMPARE(uniform3.m_type, GLenum(GL_FLOAT_VEC3));
805 QCOMPARE(uniform3.m_name, QStringLiteral("multiplierVec3"));
806
807 const ShaderUniform uniform4 = activeUniforms.at(i: 3);
808 QCOMPARE(uniform4.m_location, shaderProgram.uniformLocation("multiplierVec4"));
809 QCOMPARE(uniform4.m_offset, -1);
810 QCOMPARE(uniform4.m_blockIndex, -1);
811 QCOMPARE(uniform4.m_arrayStride, -1);
812 QCOMPARE(uniform4.m_matrixStride, -1);
813 QCOMPARE(uniform4.m_size, 1);
814 QCOMPARE(uniform4.m_type, GLenum(GL_FLOAT_VEC4));
815 QCOMPARE(uniform4.m_name, QStringLiteral("multiplierVec4"));
816 }
817
818 void programShaderStorageBlock()
819 {
820 if (!m_initializationSuccessful)
821 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
822 // Not supported by GL2
823 }
824
825 void releaseFrameBufferObject()
826 {
827 if (!m_initializationSuccessful)
828 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
829 if (!m_fboFuncs)
830 QSKIP("FBO not supported by OpenGL 2.0");
831 // GIVEN
832 GLuint fboId;
833 m_fboFuncs->glGenFramebuffers(n: 1, framebuffers: &fboId);
834
835 // THEN
836 QVERIFY(fboId != 0);
837
838 // WHEN
839 m_glHelper.releaseFrameBufferObject(frameBufferId: fboId);
840
841 // THEN
842 QVERIFY(!m_fboFuncs->glIsFramebuffer(fboId));
843 }
844
845 void setMSAAEnabled()
846 {
847 if (!m_initializationSuccessful)
848 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
849
850 // GIVEN
851 m_func->glDisable(GL_MULTISAMPLE);
852
853 // THEN
854 QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
855
856 // WHEN
857 m_glHelper.setMSAAEnabled(true);
858
859 // THEN
860 QVERIFY(m_func->glIsEnabled(GL_MULTISAMPLE));
861
862 // WHEN
863 m_glHelper.setMSAAEnabled(false);
864
865 // THEN
866 QVERIFY(!m_func->glIsEnabled(GL_MULTISAMPLE));
867 }
868
869 void setAlphaCoverageEnabled()
870 {
871 if (!m_initializationSuccessful)
872 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
873
874 // GIVEN
875 m_func->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
876
877 // THEN
878 QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
879
880 // WHEN
881 m_glHelper.setAlphaCoverageEnabled(true);
882
883 // THEN
884 QVERIFY(m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
885
886 // WHEN
887 m_glHelper.setAlphaCoverageEnabled(false);
888
889 // THEN
890 QVERIFY(!m_func->glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE));
891 }
892
893 void setClipPlane()
894 {
895 if (!m_initializationSuccessful)
896 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
897
898 // Deprecated in 3.3 core
899 }
900
901 void setSeamlessCubemap()
902 {
903 if (!m_initializationSuccessful)
904 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
905 // Not supported in GL2
906 }
907
908 void setVerticesPerPatch()
909 {
910 // Not supported in GL2
911 }
912
913#define SUPPORTS_FEATURE(Feature, IsSupported) \
914 QVERIFY(m_glHelper.supportsFeature(Feature) == IsSupported);
915
916 void supportsFeature()
917 {
918 SUPPORTS_FEATURE(GraphicsHelperInterface::MRT, (m_fboFuncs != nullptr));
919 SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, false);
920 SUPPORTS_FEATURE(GraphicsHelperInterface::BindableFragmentOutputs, false);
921 SUPPORTS_FEATURE(GraphicsHelperInterface::PrimitiveRestart, false);
922 SUPPORTS_FEATURE(GraphicsHelperInterface::RenderBufferDimensionRetrieval, false);
923 SUPPORTS_FEATURE(GraphicsHelperInterface::TextureDimensionRetrieval, true);
924 SUPPORTS_FEATURE(GraphicsHelperInterface::UniformBufferObject, false);
925 SUPPORTS_FEATURE(GraphicsHelperInterface::ShaderStorageObject, false);
926 SUPPORTS_FEATURE(GraphicsHelperInterface::Compute, false);
927 SUPPORTS_FEATURE(GraphicsHelperInterface::DrawBuffersBlend, false);
928 SUPPORTS_FEATURE(GraphicsHelperInterface::Tessellation, false);
929 SUPPORTS_FEATURE(GraphicsHelperInterface::BlitFramebuffer, false);
930 SUPPORTS_FEATURE(GraphicsHelperInterface::IndirectDrawing, false);
931 SUPPORTS_FEATURE(GraphicsHelperInterface::MapBuffer, true);
932 SUPPORTS_FEATURE(GraphicsHelperInterface::Fences, false);
933 }
934
935
936#define ADD_UNIFORM_ENTRY(FragShader, Name, Type, ComponentSize, ExpectedRawSize) \
937 QTest::newRow(#FragShader"_"#Type) << FragShader << QStringLiteral(Name) << Type << ComponentSize << ExpectedRawSize;
938
939 void uniformsByteSize_data()
940 {
941 QTest::addColumn<QByteArray>(name: "fragShader");
942 QTest::addColumn<QString>(name: "name");
943 QTest::addColumn<int>(name: "type");
944 QTest::addColumn<int>(name: "componentSize");
945 QTest::addColumn<int>(name: "expectedByteSize");
946
947 ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplier", GL_FLOAT, 1, 4);
948 ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec2", GL_FLOAT_VEC2, 1, 4 * 2);
949 ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec3",GL_FLOAT_VEC3, 1, 4 * 3);
950 ADD_UNIFORM_ENTRY(fragCodeUniformsFloat, "multiplierVec4", GL_FLOAT_VEC4, 1, 4 * 4);
951
952 ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplier", GL_INT, 1, 4);
953 ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec2", GL_INT_VEC2, 1, 4 * 2);
954 ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec3", GL_INT_VEC3, 1, 4 * 3);
955 ADD_UNIFORM_ENTRY(fragCodeUniformsInt, "multiplierVec4", GL_INT_VEC4, 1, 4 * 4);
956
957 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m2", GL_FLOAT_MAT2, 1, 4 * 2 * 2);
958 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m23", GL_FLOAT_MAT2x3, 1, 4 * 2 * 3);
959 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m32", GL_FLOAT_MAT3x2, 1, 4 * 3 * 2);
960 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m24", GL_FLOAT_MAT2x4, 1, 4 * 2 * 4);
961 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m42", GL_FLOAT_MAT4x2, 1, 4 * 4 * 2);
962 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m3", GL_FLOAT_MAT3, 1, 4 * 3 * 3);
963 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m34", GL_FLOAT_MAT3x4, 1, 4 * 3 * 4);
964 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m43", GL_FLOAT_MAT4x3, 1, 4 * 4 * 3);
965 ADD_UNIFORM_ENTRY(fragCodeUniformsFloatMatrices, "m4", GL_FLOAT_MAT4, 1, 4 * 4 * 4);
966
967 ADD_UNIFORM_ENTRY(fragCodeSamplers, "s1", GL_SAMPLER_1D, 1, 4);
968 ADD_UNIFORM_ENTRY(fragCodeSamplers, "s2", GL_SAMPLER_2D, 1, 4);
969 ADD_UNIFORM_ENTRY(fragCodeSamplers, "s3", GL_SAMPLER_3D, 1, 4);
970 ADD_UNIFORM_ENTRY(fragCodeSamplers, "scube", GL_SAMPLER_CUBE, 1, 4);
971 }
972
973 void uniformsByteSize()
974 {
975 if (!m_initializationSuccessful)
976 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
977
978 // GIVEN
979 QFETCH(QByteArray, fragShader);
980 QFETCH(QString, name);
981 QFETCH(int, type);
982 QFETCH(int, componentSize);
983 QFETCH(int, expectedByteSize);
984
985 QOpenGLShaderProgram shaderProgram;
986 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
987 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragShader);
988 QVERIFY(shaderProgram.link());
989
990 GLint location = shaderProgram.uniformLocation(name);
991 // WHEN
992 const QVector<ShaderUniform> activeUniforms = m_glHelper.programUniformsAndLocations(programId: shaderProgram.programId());
993 ShaderUniform matchingUniform;
994 for (const ShaderUniform &u : activeUniforms) {
995 if (u.m_location == location) {
996 matchingUniform = u;
997 break;
998 }
999 }
1000
1001 // THEN
1002 QCOMPARE(matchingUniform.m_location, location);
1003 QCOMPARE(matchingUniform.m_type, GLuint(type));
1004 QCOMPARE(matchingUniform.m_size, componentSize);
1005
1006 // WHEN
1007 const int computedRawByteSize = m_glHelper.uniformByteSize(description: matchingUniform);
1008
1009 // THEN
1010 QCOMPARE(expectedByteSize, computedRawByteSize);
1011
1012 // Restore
1013 m_func->glUseProgram(program: 0);
1014 }
1015
1016 void useProgram()
1017 {
1018 if (!m_initializationSuccessful)
1019 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1020
1021 // GIVEN
1022 QOpenGLShaderProgram shaderProgram;
1023 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1024 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
1025
1026 // THEN
1027 QVERIFY(shaderProgram.link());
1028
1029 GLint currentProg = 0;
1030 m_func->glGetIntegerv(GL_CURRENT_PROGRAM, params: &currentProg);
1031 QVERIFY(currentProg == 0);
1032
1033 // WHEN
1034 m_glHelper.useProgram(programId: shaderProgram.programId());
1035
1036 // THEN
1037 m_func->glGetIntegerv(GL_CURRENT_PROGRAM, params: &currentProg);
1038 QCOMPARE(GLuint(currentProg), shaderProgram.programId());
1039
1040 // WHEN
1041 m_glHelper.useProgram(programId: 0);
1042
1043 // THEN
1044 m_func->glGetIntegerv(GL_CURRENT_PROGRAM, params: &currentProg);
1045 QVERIFY(currentProg == 0);
1046 }
1047
1048 void vertexAttribDivisor()
1049 {
1050 if (!m_initializationSuccessful)
1051 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1052 // Not available in 3.2
1053 }
1054
1055 void vertexAttributePointer()
1056 {
1057 if (!m_initializationSuccessful)
1058 QSKIP("Initialization failed, OpenGL 4.3 Core functions not supported");
1059
1060 // GIVEN
1061 QOpenGLVertexArrayObject vao;
1062 vao.create();
1063 QOpenGLVertexArrayObject::Binder binder(&vao);
1064
1065 QOpenGLShaderProgram shaderProgram;
1066 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1067 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeSamplers);
1068 QVERIFY(shaderProgram.link());
1069
1070 GLint positionLocation = m_func->glGetAttribLocation(program: shaderProgram.programId(), name: "vertexPosition");
1071 GLint texCoordLocation = m_func->glGetAttribLocation(program: shaderProgram.programId(), name: "vertexTexCoord");
1072
1073 const int vertexCount = 99;
1074 QOpenGLBuffer positionBuffer(QOpenGLBuffer::VertexBuffer);
1075 positionBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
1076 positionBuffer.create();
1077 positionBuffer.bind();
1078 positionBuffer.allocate(count: vertexCount * sizeof(QVector3D));
1079
1080 QOpenGLBuffer texCoordBuffer(QOpenGLBuffer::VertexBuffer);
1081 texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
1082 texCoordBuffer.create();
1083 texCoordBuffer.allocate(count: vertexCount * sizeof(QVector2D));
1084
1085 // WHEN
1086 shaderProgram.bind();
1087 positionBuffer.bind();
1088 m_glHelper.enableVertexAttributeArray(location: positionLocation);
1089 m_glHelper.vertexAttributePointer(GL_FLOAT_VEC3, index: positionLocation, size: 3, GL_FLOAT, GL_TRUE, stride: 0, pointer: 0);
1090
1091 texCoordBuffer.bind();
1092 m_glHelper.enableVertexAttributeArray(location: texCoordLocation);
1093 m_glHelper.vertexAttributePointer(GL_FLOAT_VEC2, index: texCoordLocation, size: 2, GL_FLOAT, GL_TRUE, stride: 0, pointer: 0);
1094
1095 // THEN
1096 const GLint error = m_func->glGetError();
1097 QVERIFY(error == 0);
1098 }
1099
1100 void glUniform1fv()
1101 {
1102 if (!m_initializationSuccessful)
1103 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1104
1105 // GIVEN
1106 QOpenGLShaderProgram shaderProgram;
1107 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1108 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
1109 QVERIFY(shaderProgram.link());
1110
1111 // WHEN
1112 m_func->glUseProgram(program: shaderProgram.programId());
1113 GLfloat value = 883.0f;
1114 const GLint location = shaderProgram.uniformLocation(name: "multiplier");
1115 m_glHelper.glUniform1fv(location, count: 1, value: &value);
1116
1117 // THEN
1118 GLfloat setValue = 0.0f;
1119 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: &setValue);
1120 QCOMPARE(value, setValue);
1121
1122 // Restore
1123 m_func->glUseProgram(program: 0);
1124 }
1125
1126 void glUniform2fv()
1127 {
1128 if (!m_initializationSuccessful)
1129 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1130
1131 // GIVEN
1132 QOpenGLShaderProgram shaderProgram;
1133 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1134 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
1135 QVERIFY(shaderProgram.link());
1136
1137 // WHEN
1138 m_func->glUseProgram(program: shaderProgram.programId());
1139 GLfloat values[2] = { 383.0f, 427.0f };
1140 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec2");
1141 m_glHelper.glUniform2fv(location, count: 1, value: values);
1142
1143 // THEN
1144 GLfloat setValues[2] = { 0.0f, 0.0f };
1145 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1146 for (int i = 0; i < 2; ++i)
1147 QCOMPARE(setValues[i], values[i]);
1148
1149 // Restore
1150 m_func->glUseProgram(program: 0);
1151 }
1152
1153 void glUniform3fv()
1154 {
1155 if (!m_initializationSuccessful)
1156 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1157
1158 // GIVEN
1159 QOpenGLShaderProgram shaderProgram;
1160 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1161 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
1162 QVERIFY(shaderProgram.link());
1163
1164 // WHEN
1165 m_func->glUseProgram(program: shaderProgram.programId());
1166 GLfloat values[3] = { 572.0f, 1340.0f, 1584.0f };
1167 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec3");
1168 m_glHelper.glUniform3fv(location, count: 1, value: values);
1169
1170 // THEN
1171 GLfloat setValues[3] = { 0.0f, 0.0f, 0.0f };
1172 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1173 for (int i = 0; i < 3; ++i)
1174 QCOMPARE(setValues[i], values[i]);
1175
1176 // Restore
1177 m_func->glUseProgram(program: 0);
1178 }
1179
1180 void glUniform4fv()
1181 {
1182 if (!m_initializationSuccessful)
1183 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1184
1185 // GIVEN
1186 QOpenGLShaderProgram shaderProgram;
1187 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1188 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloat);
1189 QVERIFY(shaderProgram.link());
1190
1191 // WHEN
1192 m_func->glUseProgram(program: shaderProgram.programId());
1193 GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
1194 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec4");
1195 m_glHelper.glUniform4fv(location, count: 1, value: values);
1196
1197 // THEN
1198 GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1199 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1200 for (int i = 0; i < 4; ++i)
1201 QCOMPARE(setValues[i], values[i]);
1202
1203 // Restore
1204 m_func->glUseProgram(program: 0);
1205 }
1206
1207 void glUniform1iv()
1208 {
1209 if (!m_initializationSuccessful)
1210 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1211
1212 // GIVEN
1213 QOpenGLShaderProgram shaderProgram;
1214 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1215 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsInt);
1216 QVERIFY(shaderProgram.link());
1217
1218 // WHEN
1219 m_func->glUseProgram(program: shaderProgram.programId());
1220 GLint value = 883;
1221 const GLint location = shaderProgram.uniformLocation(name: "multiplier");
1222 m_glHelper.glUniform1iv(location, count: 1, value: &value);
1223
1224 // THEN
1225 GLint setValue = 0;
1226 m_func->glGetUniformiv(program: shaderProgram.programId(), location, params: &setValue);
1227 QCOMPARE(value, setValue);
1228
1229 // Restore
1230 m_func->glUseProgram(program: 0);
1231 }
1232
1233 void glUniform2iv()
1234 {
1235 if (!m_initializationSuccessful)
1236 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1237
1238 // GIVEN
1239 QOpenGLShaderProgram shaderProgram;
1240 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1241 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsInt);
1242 QVERIFY(shaderProgram.link());
1243
1244 // WHEN
1245 m_func->glUseProgram(program: shaderProgram.programId());
1246 GLint values[2] = { 383, 427 };
1247 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec2");
1248 m_glHelper.glUniform2iv(location, count: 1, value: values);
1249
1250 // THEN
1251 GLint setValues[2] = { 0, 0 };
1252 m_func->glGetUniformiv(program: shaderProgram.programId(), location, params: setValues);
1253 for (int i = 0; i < 2; ++i)
1254 QCOMPARE(values[i], setValues[i]);
1255
1256 // Restore
1257 m_func->glUseProgram(program: 0);
1258 }
1259
1260 void glUniform3iv()
1261 {
1262 if (!m_initializationSuccessful)
1263 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1264
1265 // GIVEN
1266 QOpenGLShaderProgram shaderProgram;
1267 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1268 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsInt);
1269 QVERIFY(shaderProgram.link());
1270
1271 // WHEN
1272 m_func->glUseProgram(program: shaderProgram.programId());
1273 GLint values[3] = { 572, 1340, 1584 };
1274 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec3");
1275 m_glHelper.glUniform3iv(location, count: 1, value: values);
1276
1277 // THEN
1278 GLint setValues[3] = { 0, 0, 0 };
1279 m_func->glGetUniformiv(program: shaderProgram.programId(), location, params: setValues);
1280 for (int i = 0; i < 3; ++i)
1281 QCOMPARE(values[i], setValues[i]);
1282
1283 // Restore
1284 m_func->glUseProgram(program: 0);
1285 }
1286
1287 void glUniform4iv()
1288 {
1289 if (!m_initializationSuccessful)
1290 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1291
1292 // GIVEN
1293 QOpenGLShaderProgram shaderProgram;
1294 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1295 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsInt);
1296 QVERIFY(shaderProgram.link());
1297
1298 // WHEN
1299 m_func->glUseProgram(program: shaderProgram.programId());
1300 GLint values[4] = { 454, 350, 883, 355 };
1301 const GLint location = shaderProgram.uniformLocation(name: "multiplierVec4");
1302 m_glHelper.glUniform4iv(location, count: 1, value: values);
1303
1304 // THEN
1305 GLint setValues[4] = { 0, 0, 0, 0 };
1306 m_func->glGetUniformiv(program: shaderProgram.programId(), location, params: setValues);
1307 for (int i = 0; i < 4; ++i)
1308 QCOMPARE(values[i], setValues[i]);
1309
1310 // Restore
1311 m_func->glUseProgram(program: 0);
1312 }
1313
1314 void glUniform1uiv()
1315 {
1316 if (!m_initializationSuccessful)
1317 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1318 // Not supported by GL2
1319 }
1320
1321 void glUniform2uiv()
1322 {
1323 if (!m_initializationSuccessful)
1324 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1325 // Not supported by GL2
1326 }
1327
1328 void glUniform3uiv()
1329 {
1330 if (!m_initializationSuccessful)
1331 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1332 // Not supported by GL2
1333 }
1334
1335 void glUniform4uiv()
1336 {
1337 if (!m_initializationSuccessful)
1338 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1339 // Not supported by GL2
1340 }
1341
1342 void glUniformMatrix2fv()
1343 {
1344 if (!m_initializationSuccessful)
1345 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1346
1347 // GIVEN
1348 QOpenGLShaderProgram shaderProgram;
1349 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1350 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloatMatrices);
1351 QVERIFY(shaderProgram.link());
1352
1353 // WHEN
1354 m_func->glUseProgram(program: shaderProgram.programId());
1355 GLfloat values[4] = { 454.0f, 350.0f, 883.0f, 355.0f };
1356 const GLint location = shaderProgram.uniformLocation(name: "m2");
1357 m_glHelper.glUniformMatrix2fv(location, count: 1, value: values);
1358
1359 // THEN
1360 GLfloat setValues[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
1361 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1362 for (int i = 0; i < 4; ++i)
1363 QCOMPARE(values[i], setValues[i]);
1364
1365 // Restore
1366 m_func->glUseProgram(program: 0);
1367 }
1368
1369 void glUniformMatrix3fv()
1370 {
1371 if (!m_initializationSuccessful)
1372 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1373
1374 // GIVEN
1375 QOpenGLShaderProgram shaderProgram;
1376 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1377 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloatMatrices);
1378 QVERIFY(shaderProgram.link());
1379
1380 // WHEN
1381 m_func->glUseProgram(program: shaderProgram.programId());
1382 GLfloat values[9] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f };
1383 const GLint location = shaderProgram.uniformLocation(name: "m3");
1384 m_glHelper.glUniformMatrix3fv(location, count: 1, value: values);
1385
1386 // THEN
1387 GLfloat setValues[9] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
1388 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1389 for (int i = 0; i < 9; ++i)
1390 QCOMPARE(values[i], setValues[i]);
1391
1392 // Restore
1393 m_func->glUseProgram(program: 0);
1394 }
1395
1396 void glUniformMatrix4fv()
1397 {
1398 if (!m_initializationSuccessful)
1399 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1400
1401 // GIVEN
1402 QOpenGLShaderProgram shaderProgram;
1403 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Vertex, source: vertCode);
1404 shaderProgram.addShaderFromSourceCode(type: QOpenGLShader::Fragment, source: fragCodeUniformsFloatMatrices);
1405 QVERIFY(shaderProgram.link());
1406
1407 // WHEN
1408 m_func->glUseProgram(program: shaderProgram.programId());
1409 GLfloat values[16] = { 454.0f, 350.0f, 883.0f, 355.0f, 1340.0f, 1584.0f, 1200.0f, 427.0f, 396.0f, 1603.0f, 55.0f, 5.7f, 383.0f, 6.2f, 5.3f, 327.0f };
1410 const GLint location = shaderProgram.uniformLocation(name: "m4");
1411 m_glHelper.glUniformMatrix4fv(location, count: 1, value: values);
1412
1413 // THEN
1414 GLfloat setValues[16] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
1415 m_func->glGetUniformfv(program: shaderProgram.programId(), location, params: setValues);
1416 for (int i = 0; i < 16; ++i)
1417 QCOMPARE(values[i], setValues[i]);
1418
1419 // Restore
1420 m_func->glUseProgram(program: 0);
1421 }
1422
1423 void glUniformMatrix2x3fv()
1424 {
1425 if (!m_initializationSuccessful)
1426 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1427 // Not supported by GL2
1428 }
1429
1430 void glUniformMatrix3x2fv()
1431 {
1432 if (!m_initializationSuccessful)
1433 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1434 // Not supported by GL2
1435 }
1436
1437 void glUniformMatrix2x4fv()
1438 {
1439 if (!m_initializationSuccessful)
1440 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1441 // Not supported by GL2
1442 }
1443
1444 void glUniformMatrix4x2fv()
1445 {
1446 if (!m_initializationSuccessful)
1447 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1448 // Not supported by GL2
1449 }
1450
1451 void glUniformMatrix3x4fv()
1452 {
1453 if (!m_initializationSuccessful)
1454 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1455 // Not supported by GL2
1456 }
1457
1458 void glUniformMatrix4x3fv()
1459 {
1460 if (!m_initializationSuccessful)
1461 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1462 // Not supported by GL2
1463 }
1464
1465 void blitFramebuffer()
1466 {
1467 if (!m_initializationSuccessful)
1468 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1469 // Not supported by GL2
1470 }
1471
1472#define ADD_GL_TYPE_ENTRY(Type, Expected) \
1473 QTest::newRow(#Type) << Type << Expected;
1474
1475 void uniformTypeFromGLType_data()
1476 {
1477 QTest::addColumn<int>(name: "glType");
1478 QTest::addColumn<UniformType>(name: "expected");
1479
1480 ADD_GL_TYPE_ENTRY(GL_FLOAT, UniformType::Float);
1481 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
1482 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
1483 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
1484 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC2, UniformType::Vec2);
1485 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
1486 ADD_GL_TYPE_ENTRY(GL_FLOAT_VEC3, UniformType::Vec3);
1487 ADD_GL_TYPE_ENTRY(GL_INT, UniformType::Int);
1488 ADD_GL_TYPE_ENTRY(GL_INT_VEC2, UniformType::IVec2);
1489 ADD_GL_TYPE_ENTRY(GL_INT_VEC3, UniformType::IVec3);
1490 ADD_GL_TYPE_ENTRY(GL_INT_VEC4, UniformType::IVec4);
1491 ADD_GL_TYPE_ENTRY(GL_BOOL, UniformType::Bool);
1492 ADD_GL_TYPE_ENTRY(GL_BOOL_VEC2, UniformType::BVec2);
1493 ADD_GL_TYPE_ENTRY(GL_BOOL_VEC3, UniformType::BVec3);
1494 ADD_GL_TYPE_ENTRY(GL_BOOL_VEC4, UniformType::BVec4);
1495 ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT2, UniformType::Mat2);
1496 ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT3, UniformType::Mat3);
1497 ADD_GL_TYPE_ENTRY(GL_FLOAT_MAT4, UniformType::Mat4);
1498 ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D, UniformType::Sampler);
1499 ADD_GL_TYPE_ENTRY(GL_SAMPLER_1D_SHADOW, UniformType::Sampler);
1500 ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D, UniformType::Sampler);
1501 ADD_GL_TYPE_ENTRY(GL_SAMPLER_2D_SHADOW, UniformType::Sampler);
1502 ADD_GL_TYPE_ENTRY(GL_SAMPLER_3D, UniformType::Sampler);
1503 ADD_GL_TYPE_ENTRY(GL_SAMPLER_CUBE, UniformType::Sampler);
1504 }
1505
1506 void uniformTypeFromGLType()
1507 {
1508 // GIVEN
1509 QFETCH(int, glType);
1510 QFETCH(UniformType, expected);
1511
1512 // WHEN
1513 UniformType computed = m_glHelper.uniformTypeFromGLType(glType);
1514
1515 // THEN
1516 QCOMPARE(computed, expected);
1517 }
1518
1519 void drawBuffer()
1520 {
1521 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1522 // Not supported by GL2
1523 }
1524
1525 void readBuffer()
1526 {
1527 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1528 // Not supported by GL2
1529 }
1530
1531 void fenceSync()
1532 {
1533 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1534 // Not supported by GL2
1535 }
1536
1537 void clientWaitSync()
1538 {
1539 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1540 // Not supported by GL2
1541 }
1542
1543 void waitSync()
1544 {
1545 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1546 // Not supported by GL2
1547 }
1548
1549 void wasSyncSignaled()
1550 {
1551 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1552 // Not supported by GL2
1553 }
1554
1555 void deleteSync()
1556 {
1557 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1558 // Not supported by GL2
1559 }
1560
1561 void rasterMode()
1562 {
1563 if (!m_initializationSuccessful)
1564 QSKIP("Initialization failed, OpenGL 2.0 functions not supported");
1565
1566 m_func->glGetError();
1567
1568 // WHEN
1569 m_glHelper.rasterMode(GL_FRONT_AND_BACK, GL_LINE);
1570
1571 // THEN
1572 const GLint error = m_func->glGetError();
1573 QVERIFY(error == 0);
1574 GLint p;
1575 m_func->glGetIntegerv(GL_POLYGON_MODE, params: &p);
1576 QCOMPARE(p, GL_LINE);
1577 }
1578
1579private:
1580 QScopedPointer<QWindow> m_window;
1581 QOpenGLContext m_glContext;
1582 GraphicsHelperGL2 m_glHelper;
1583 QOpenGLFunctions_2_0 *m_func = nullptr;
1584 QOpenGLExtension_ARB_framebuffer_object *m_fboFuncs = nullptr;
1585 bool m_initializationSuccessful = false;
1586};
1587
1588QT_END_NAMESPACE
1589
1590#endif
1591
1592int main(int argc, char *argv[])
1593{
1594#ifdef TEST_SHOULD_BE_PERFORMED
1595 QGuiApplication app(argc, argv);
1596 app.setAttribute(attribute: Qt::AA_Use96Dpi, on: true);
1597 tst_GraphicsHelperGL2 tc;
1598 QTEST_SET_MAIN_SOURCE_PATH
1599 return QTest::qExec(testObject: &tc, argc, argv);
1600#endif
1601 return 0;
1602}
1603
1604#ifdef TEST_SHOULD_BE_PERFORMED
1605#include "tst_graphicshelpergl2.moc"
1606#endif
1607

source code of qt3d/tests/auto/render/opengl/graphicshelpergl2/tst_graphicshelpergl2.cpp