1 /****************************************************************************
2 **
3 ** Copyright (C) 2008-2012 NVIDIA Corporation.
4 ** Copyright (C) 2019 The Qt Company Ltd.
5 ** Contact: https://www.qt.io/licensing/
6 **
7 ** This file is part of Qt Quick 3D.
8 **
9 ** $QT_BEGIN_LICENSE:GPL$
10 ** Commercial License Usage
11 ** Licensees holding valid commercial Qt licenses may use this file in
12 ** accordance with the commercial license agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and The Qt Company. For licensing terms
15 ** and conditions see https://www.qt.io/terms-conditions. For further
16 ** information use the contact form at https://www.qt.io/contact-us.
17 **
18 ** GNU General Public License Usage
19 ** Alternatively, this file may be used under the terms of the GNU
20 ** General Public License version 3 or (at your option) any later version
21 ** approved by the KDE Free Qt Foundation. The licenses are as published by
22 ** the Free Software Foundation and appearing in the file LICENSE.GPL3
23 ** included in the packaging of this file. Please review the following
24 ** information to ensure the GNU General Public License requirements will
25 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
26 **
27 ** $QT_END_LICENSE$
28 **
29 ****************************************************************************/
30 
31 #include <QtQuick3DRender/private/qssgrenderbackendgl4_p.h>
32 #include <QtQuick3DRender/private/qssgrenderbackendinputassemblergl_p.h>
33 #include <QtQuick3DRender/private/qssgrenderbackendshaderprogramgl_p.h>
34 
35 #include <QtQuick3DRender/private/qssgopenglextensions_p.h>
36 
37 QT_BEGIN_NAMESPACE
38 
39 #ifdef RENDER_BACKEND_LOG_GL_ERRORS
40 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError(#x, __FILE__, __LINE__)
41 #else
42 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError()
43 #endif
44 
45 #define GL_CALL_EXTRA_FUNCTION(x)                                                                                      \
46     m_glExtraFunctions->x;                                                                                             \
47     RENDER_LOG_ERROR_PARAMS(x);
48 
49 #if defined(QT_OPENGL_ES)
50 #define GL_CALL_QSSG_EXT(x)                                                                                          \
51     m_QSSGExtensions->x;                                                                                             \
52     RENDER_LOG_ERROR_PARAMS(x);
53 #else
54 #define GL_CALL_DIRECTSTATE_EXT(x)                                                                                     \
55     m_directStateAccess->x;                                                                                            \
56     RENDER_LOG_ERROR_PARAMS(x);
57 #define GL_CALL_QSSG_EXT(x)                                                                                          \
58     m_QSSGExtensions->x;                                                                                             \
59     RENDER_LOG_ERROR_PARAMS(x);
60 #endif
61 
62 #ifndef GL_GEOMETRY_SHADER_EXT
63 #define GL_GEOMETRY_SHADER_EXT 0x8DD9
64 #endif
65 
66 namespace QSSGGlExtStrings {
extTess()67 QByteArray extTess()
68 {
69     return QByteArrayLiteral("GL_ARB_tessellation_shader");
70 }
extGeometry()71 QByteArray extGeometry()
72 {
73     return QByteArrayLiteral("GL_EXT_geometry_shader4");
74 }
arbCompute()75 QByteArray arbCompute()
76 {
77     return QByteArrayLiteral("GL_ARB_compute_shader");
78 }
arbStorageBuffer()79 QByteArray arbStorageBuffer()
80 {
81     return QByteArrayLiteral("GL_ARB_shader_storage_buffer_object");
82 }
arbProgInterface()83 QByteArray arbProgInterface()
84 {
85     return QByteArrayLiteral("GL_ARB_program_interface_query");
86 }
arbShaderImageLoadStore()87 QByteArray arbShaderImageLoadStore()
88 {
89     return QByteArrayLiteral("GL_ARB_shader_image_load_store");
90 }
nvBlendAdvanced()91 QByteArray nvBlendAdvanced()
92 {
93     return QByteArrayLiteral("GL_NV_blend_equation_advanced");
94 }
khrBlendAdvanced()95 QByteArray khrBlendAdvanced()
96 {
97     return QByteArrayLiteral("GL_KHR_blend_equation_advanced");
98 }
nvBlendAdvancedCoherent()99 QByteArray nvBlendAdvancedCoherent()
100 {
101     return QByteArrayLiteral("GL_NV_blend_equation_advanced_coherent");
102 }
khrBlendAdvancedCoherent()103 QByteArray khrBlendAdvancedCoherent()
104 {
105     return QByteArrayLiteral("GL_KHR_blend_equation_advanced_coherent");
106 }
107 }
108 
109 /// constructor
QSSGRenderBackendGL4Impl(const QSurfaceFormat & format)110 QSSGRenderBackendGL4Impl::QSSGRenderBackendGL4Impl(const QSurfaceFormat &format)
111     : QSSGRenderBackendGL3Impl(format)
112 {
113     // get extension count
114     GLint numExtensions = 0;
115     GL_CALL_EXTRA_FUNCTION(glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions));
116 
117     for (qint32 i = 0; i < numExtensions; i++) {
118         const GLubyte *glExt = GL_CALL_EXTRA_FUNCTION(glGetStringi(GL_EXTENSIONS, GLuint(i)));
119         const QByteArray extensionString(reinterpret_cast<const char *>(glExt));
120 
121         // search for extension
122         if (!m_backendSupport.caps.bits.bTessellationSupported && QSSGGlExtStrings::extTess().compare(extensionString) == 0) {
123             m_backendSupport.caps.bits.bTessellationSupported = true;
124         } else if (!m_backendSupport.caps.bits.bComputeSupported && QSSGGlExtStrings::arbCompute().compare(extensionString) == 0) {
125             m_backendSupport.caps.bits.bComputeSupported = true;
126         } else if (!m_backendSupport.caps.bits.bGeometrySupported
127                    && QSSGGlExtStrings::extGeometry().compare(extensionString) == 0) {
128             m_backendSupport.caps.bits.bGeometrySupported = true;
129         } else if (!m_backendSupport.caps.bits.bStorageBufferSupported
130                    && QSSGGlExtStrings::arbStorageBuffer().compare(extensionString) == 0) {
131             m_backendSupport.caps.bits.bStorageBufferSupported = true;
132         } else if (!m_backendSupport.caps.bits.bProgramInterfaceSupported
133                    && QSSGGlExtStrings::arbProgInterface().compare(extensionString) == 0) {
134             m_backendSupport.caps.bits.bProgramInterfaceSupported = true;
135         } else if (!m_backendSupport.caps.bits.bShaderImageLoadStoreSupported
136                    && QSSGGlExtStrings::arbShaderImageLoadStore().compare(extensionString) == 0) {
137             m_backendSupport.caps.bits.bShaderImageLoadStoreSupported = true;
138         } else if (!m_backendSupport.caps.bits.bNVAdvancedBlendSupported
139                    && QSSGGlExtStrings::nvBlendAdvanced().compare(extensionString) == 0) {
140             m_backendSupport.caps.bits.bNVAdvancedBlendSupported = true;
141         } else if (!m_backendSupport.caps.bits.bNVBlendCoherenceSupported
142                    && QSSGGlExtStrings::nvBlendAdvancedCoherent().compare(extensionString) == 0) {
143             m_backendSupport.caps.bits.bNVBlendCoherenceSupported = true;
144         } else if (!m_backendSupport.caps.bits.bKHRAdvancedBlendSupported
145                    && QSSGGlExtStrings::khrBlendAdvanced().compare(extensionString) == 0) {
146             m_backendSupport.caps.bits.bKHRAdvancedBlendSupported = true;
147         } else if (!m_backendSupport.caps.bits.bKHRBlendCoherenceSupported
148                    && QSSGGlExtStrings::khrBlendAdvancedCoherent().compare(extensionString) == 0) {
149             m_backendSupport.caps.bits.bKHRBlendCoherenceSupported = true;
150         }
151     }
152 
153     // always true for GL4.1 and GLES 3.1 devices
154     m_backendSupport.caps.bits.bMsTextureSupported = true;
155     m_backendSupport.caps.bits.bProgramPipelineSupported = true;
156 
157     if (!isESCompatible()) {
158         // TODO: investigate GL 4.0 support
159         // we expect minimum GL 4.1 context anything beyond is handeled via extensions
160         // Tessellation is always supported on none ES systems which support >=GL4
161         m_backendSupport.caps.bits.bTessellationSupported = true;
162         // geometry shader is always supported on none ES systems which support >=GL4 ( actually
163         // 3.2 already )
164         m_backendSupport.caps.bits.bGeometrySupported = true;
165     } else {
166         // always true for GLES 3.1 devices
167         m_backendSupport.caps.bits.bComputeSupported = true;
168         m_backendSupport.caps.bits.bProgramInterfaceSupported = true;
169         m_backendSupport.caps.bits.bStorageBufferSupported = true;
170         m_backendSupport.caps.bits.bShaderImageLoadStoreSupported = true;
171     }
172 
173 #if !defined(QT_OPENGL_ES)
174     // Initialize extensions
175     m_directStateAccess = new QOpenGLExtension_EXT_direct_state_access();
176     m_directStateAccess->initializeOpenGLFunctions();
177 #endif
178 }
179 
180 /// destructor
~QSSGRenderBackendGL4Impl()181 QSSGRenderBackendGL4Impl::~QSSGRenderBackendGL4Impl()
182 {
183 #if !defined(QT_OPENGL_ES)
184     delete m_directStateAccess;
185 #endif
186 }
187 
getShadingLanguageVersion()188 QByteArray QSSGRenderBackendGL4Impl::getShadingLanguageVersion()
189 {
190     // Re-use the implementation from the GL3 backend if the surface is GL ES 3
191     // (should only be the case for 3.1 and greater).
192     if (m_format.renderableType() == QSurfaceFormat::OpenGLES && m_format.majorVersion() == 3)
193         return QSSGRenderBackendGL3Impl::getShadingLanguageVersion();
194 
195     Q_ASSERT(m_format.majorVersion() >= 4);
196     QByteArray ver("#version 400\n");
197     if (m_format.majorVersion() == 4)
198         ver[10] = '0' + char(m_format.minorVersion());
199 
200     return ver;
201 }
202 
getRenderContextType() const203 QSSGRenderContextType QSSGRenderBackendGL4Impl::getRenderContextType() const
204 {
205     // Re-use the implementation from the GL3 backend if the surface is GL ES 3
206     // (should only be the case for 3.1 and greater).
207     if (m_format.renderableType() == QSurfaceFormat::OpenGLES && m_format.majorVersion() == 3)
208         return QSSGRenderBackendGL3Impl::getRenderContextType();
209 
210     Q_ASSERT(m_format.majorVersion() >= 4);
211     return QSSGRenderContextType::GL4;
212 }
213 
createTextureStorage2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 levels,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height)214 void QSSGRenderBackendGL4Impl::createTextureStorage2D(QSSGRenderBackendTextureObject to,
215                                                         QSSGRenderTextureTargetType target,
216                                                         qint32 levels,
217                                                         QSSGRenderTextureFormat internalFormat,
218                                                         qint32 width,
219                                                         qint32 height)
220 {
221     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
222     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
223     setActiveTexture(GL_TEXTURE0);
224     GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
225 
226     // up to now compressed is not supported
227     Q_ASSERT(internalFormat.isUncompressedTextureFormat());
228 
229     GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
230     GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
231 
232     GL_CALL_EXTRA_FUNCTION(glTexStorage2D(glTarget, levels, glInternalFormat, GLsizei(width), GLsizei(height)));
233 
234     GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
235 }
236 
setMultisampledTextureData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 samples,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,bool fixedsamplelocations)237 void QSSGRenderBackendGL4Impl::setMultisampledTextureData2D(QSSGRenderBackendTextureObject to,
238                                                               QSSGRenderTextureTargetType target,
239                                                               qint32 samples,
240                                                               QSSGRenderTextureFormat internalFormat,
241                                                               qint32 width,
242                                                               qint32 height,
243                                                               bool fixedsamplelocations)
244 {
245     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
246     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
247     setActiveTexture(GL_TEXTURE0);
248     GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
249 
250     QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
251     internalFormat = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), internalFormat, swizzleMode);
252 
253     GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
254 
255     if (internalFormat.isUncompressedTextureFormat())
256         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
257     else if (internalFormat.isDepthTextureFormat())
258         GLConversion::fromDepthTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
259     GL_CALL_EXTRA_FUNCTION(
260             glTexStorage2DMultisample(glTarget, GLsizei(samples), glInternalFormat, GLsizei(width), GLsizei(height), fixedsamplelocations));
261 
262     GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
263 }
264 
createTessControlShader(QSSGByteView source,QByteArray & errorMessage,bool binary)265 QSSGRenderBackend::QSSGRenderBackendTessControlShaderObject QSSGRenderBackendGL4Impl::createTessControlShader(
266         QSSGByteView source,
267         QByteArray &errorMessage,
268         bool binary)
269 {
270 #if !defined(QT_OPENGL_ES)
271     GLuint shaderID = GL_CALL_EXTRA_FUNCTION(glCreateShader(GL_TESS_CONTROL_SHADER));
272 #else
273     GLuint shaderID = 0;
274 #endif
275     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
276         GL_CALL_EXTRA_FUNCTION(glDeleteShader(shaderID));
277         shaderID = 0;
278     }
279 
280     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendTessControlShaderObject>(quintptr(shaderID));
281 }
282 
createTessEvaluationShader(QSSGByteView source,QByteArray & errorMessage,bool binary)283 QSSGRenderBackend::QSSGRenderBackendTessEvaluationShaderObject QSSGRenderBackendGL4Impl::createTessEvaluationShader(
284         QSSGByteView source,
285         QByteArray &errorMessage,
286         bool binary)
287 {
288 #if !defined(QT_OPENGL_ES)
289     GLuint shaderID = GL_CALL_EXTRA_FUNCTION(glCreateShader(GL_TESS_EVALUATION_SHADER));
290 #else
291     GLuint shaderID = 0;
292 #endif
293 
294     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
295         GL_CALL_EXTRA_FUNCTION(glDeleteShader(shaderID));
296         shaderID = 0;
297     }
298 
299     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendTessEvaluationShaderObject>(quintptr(shaderID));
300 }
301 
createGeometryShader(QSSGByteView source,QByteArray & errorMessage,bool binary)302 QSSGRenderBackend::QSSGRenderBackendGeometryShaderObject QSSGRenderBackendGL4Impl::createGeometryShader(QSSGByteView source,
303                                                                                                               QByteArray &errorMessage,
304                                                                                                               bool binary)
305 {
306 #if defined(QT_OPENGL_ES)
307     GLuint shaderID = GL_CALL_EXTRA_FUNCTION(glCreateShader(GL_GEOMETRY_SHADER_EXT));
308 #else
309     GLuint shaderID = GL_CALL_EXTRA_FUNCTION(glCreateShader(GL_GEOMETRY_SHADER));
310 #endif
311     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
312         GL_CALL_EXTRA_FUNCTION(glDeleteShader(shaderID));
313         shaderID = 0;
314     }
315 
316     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendGeometryShaderObject>(quintptr(shaderID));
317 }
318 
setPatchVertexCount(QSSGRenderBackendInputAssemblerObject iao,quint32 count)319 void QSSGRenderBackendGL4Impl::setPatchVertexCount(QSSGRenderBackendInputAssemblerObject iao, quint32 count)
320 {
321     Q_ASSERT(iao);
322     Q_ASSERT(count);
323     QSSGRenderBackendInputAssemblerGL *inputAssembler = reinterpret_cast<QSSGRenderBackendInputAssemblerGL *>(iao);
324     inputAssembler->m_patchVertexCount = count;
325 }
326 
setMemoryBarrier(QSSGRenderBufferBarrierFlags barriers)327 void QSSGRenderBackendGL4Impl::setMemoryBarrier(QSSGRenderBufferBarrierFlags barriers)
328 {
329     GL_CALL_EXTRA_FUNCTION(glMemoryBarrier(m_conversion.fromMemoryBarrierFlagsToGL(barriers)));
330 }
331 
bindImageTexture(QSSGRenderBackendTextureObject to,quint32 unit,qint32 level,bool layered,qint32 layer,QSSGRenderImageAccessType access,QSSGRenderTextureFormat format)332 void QSSGRenderBackendGL4Impl::bindImageTexture(QSSGRenderBackendTextureObject to,
333                                                   quint32 unit,
334                                                   qint32 level,
335                                                   bool layered,
336                                                   qint32 layer,
337                                                   QSSGRenderImageAccessType access,
338                                                   QSSGRenderTextureFormat format)
339 {
340     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
341 
342     GL_CALL_EXTRA_FUNCTION(glBindImageTexture(unit,
343                                               texID,
344                                               level,
345                                               layered,
346                                               layer,
347                                               m_conversion.fromImageAccessToGL(access),
348                                               m_conversion.fromImageFormatToGL(format)));
349 }
350 
getStorageBufferCount(QSSGRenderBackendShaderProgramObject po)351 qint32 QSSGRenderBackendGL4Impl::getStorageBufferCount(QSSGRenderBackendShaderProgramObject po)
352 {
353     GLint numStorageBuffers = 0;
354 
355     // The static, compile time condition is not ideal (it all should be run
356     // time checks), but will be replaced in the future anyway.
357 #if defined(GL_VERSION_4_3) || defined(QT_OPENGL_ES_3_1)
358     Q_ASSERT(po);
359     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
360     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
361     if (m_backendSupport.caps.bits.bProgramInterfaceSupported)
362         GL_CALL_EXTRA_FUNCTION(glGetProgramInterfaceiv(programID, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &numStorageBuffers));
363 #else
364     Q_UNUSED(po);
365 #endif
366     return numStorageBuffers;
367 }
368 
getStorageBufferInfoByID(QSSGRenderBackendShaderProgramObject po,quint32 id,quint32 nameBufSize,qint32 * paramCount,qint32 * bufferSize,qint32 * length,char * nameBuf)369 qint32 QSSGRenderBackendGL4Impl::getStorageBufferInfoByID(QSSGRenderBackendShaderProgramObject po,
370                                                             quint32 id,
371                                                             quint32 nameBufSize,
372                                                             qint32 *paramCount,
373                                                             qint32 *bufferSize,
374                                                             qint32 *length,
375                                                             char *nameBuf)
376 {
377     GLint bufferIndex = GL_INVALID_INDEX;
378 
379     // The static, compile time condition is not ideal (it all should be run
380     // time checks), but will be replaced in the future anyway.
381 #if defined(GL_VERSION_4_3) || defined(QT_OPENGL_ES_3_1)
382     Q_ASSERT(po);
383     Q_ASSERT(length);
384     Q_ASSERT(nameBuf);
385     Q_ASSERT(bufferSize);
386     Q_ASSERT(paramCount);
387     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
388     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
389     if (m_backendSupport.caps.bits.bProgramInterfaceSupported) {
390         GL_CALL_EXTRA_FUNCTION(glGetProgramResourceName(programID, GL_SHADER_STORAGE_BLOCK, id, nameBufSize, length, nameBuf));
391 
392         if (*length > 0) {
393 #define QUERY_COUNT 3
394             GLsizei actualCount;
395             GLenum props[QUERY_COUNT] = { GL_BUFFER_BINDING, GL_BUFFER_DATA_SIZE, GL_NUM_ACTIVE_VARIABLES };
396             GLint params[QUERY_COUNT];
397             GL_CALL_EXTRA_FUNCTION(
398                     glGetProgramResourceiv(programID, GL_SHADER_STORAGE_BLOCK, id, QUERY_COUNT, props, QUERY_COUNT, &actualCount, params));
399 
400             Q_ASSERT(actualCount == QUERY_COUNT);
401 
402             bufferIndex = params[0];
403             *bufferSize = params[1];
404             *paramCount = params[2];
405         }
406     }
407 #else
408     Q_UNUSED(po);
409     Q_UNUSED(id);
410     Q_UNUSED(nameBufSize);
411     Q_UNUSED(paramCount);
412     Q_UNUSED(bufferSize);
413     Q_UNUSED(length);
414     Q_UNUSED(nameBuf);
415 #endif
416     return bufferIndex;
417 }
418 
programSetStorageBuffer(quint32 index,QSSGRenderBackendBufferObject bo)419 void QSSGRenderBackendGL4Impl::programSetStorageBuffer(quint32 index, QSSGRenderBackendBufferObject bo)
420 {
421     // The static, compile time condition is not ideal (it all should be run
422     // time checks), but will be replaced in the future anyway.
423 #if defined(GL_VERSION_4_3) || defined(QT_OPENGL_ES_3_1)
424     GL_CALL_EXTRA_FUNCTION(glBindBufferBase(GL_SHADER_STORAGE_BUFFER, index, HandleToID_cast(GLuint, quintptr, bo)));
425 #else
426     Q_UNUSED(index);
427     Q_UNUSED(bo);
428 #endif
429 }
430 
setConstantValue(QSSGRenderBackendShaderProgramObject po,quint32 id,QSSGRenderShaderDataType type,qint32 count,const void * value,bool transpose)431 void QSSGRenderBackendGL4Impl::setConstantValue(QSSGRenderBackendShaderProgramObject po,
432                                                   quint32 id,
433                                                   QSSGRenderShaderDataType type,
434                                                   qint32 count,
435                                                   const void *value,
436                                                   bool transpose)
437 {
438     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
439     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
440 
441     GLenum glType = GLConversion::fromPropertyDataTypesToShaderGL(type);
442 
443     switch (glType) {
444     case GL_FLOAT:
445         GL_CALL_EXTRA_FUNCTION(glProgramUniform1fv(programID, GLint(id), count, static_cast<const GLfloat *>(value)));
446         break;
447     case GL_FLOAT_VEC2:
448         GL_CALL_EXTRA_FUNCTION(glProgramUniform2fv(programID, GLint(id), count, static_cast<const GLfloat *>(value)));
449         break;
450     case GL_FLOAT_VEC3:
451         GL_CALL_EXTRA_FUNCTION(glProgramUniform3fv(programID, GLint(id), count, static_cast<const GLfloat *>(value)));
452         break;
453     case GL_FLOAT_VEC4:
454         GL_CALL_EXTRA_FUNCTION(glProgramUniform4fv(programID, GLint(id), count, static_cast<const GLfloat *>(value)));
455         break;
456     case GL_INT:
457         GL_CALL_EXTRA_FUNCTION(glProgramUniform1iv(programID, GLint(id), count, static_cast<const GLint *>(value)));
458         break;
459     case GL_BOOL: {
460         const GLint boolValue = value ? *reinterpret_cast<const bool *>(value) : false;
461         GL_CALL_EXTRA_FUNCTION(glProgramUniform1iv(programID, GLint(id), count, &boolValue));
462     } break;
463     case GL_INT_VEC2:
464     case GL_BOOL_VEC2:
465         GL_CALL_EXTRA_FUNCTION(glProgramUniform2iv(programID, GLint(id), count, static_cast<const GLint *>(value)));
466         break;
467     case GL_INT_VEC3:
468     case GL_BOOL_VEC3:
469         GL_CALL_EXTRA_FUNCTION(glProgramUniform3iv(programID, GLint(id), count, static_cast<const GLint *>(value)));
470         break;
471     case GL_INT_VEC4:
472     case GL_BOOL_VEC4:
473         GL_CALL_EXTRA_FUNCTION(glProgramUniform4iv(programID, GLint(id), count, static_cast<const GLint *>(value)));
474         break;
475     case GL_FLOAT_MAT3:
476         GL_CALL_EXTRA_FUNCTION(glProgramUniformMatrix3fv(programID, GLint(id), count, transpose, static_cast<const GLfloat *>(value)));
477         break;
478     case GL_FLOAT_MAT4:
479         GL_CALL_EXTRA_FUNCTION(glProgramUniformMatrix4fv(programID, GLint(id), count, transpose, static_cast<const GLfloat *>(value)));
480         break;
481     case GL_IMAGE_2D:
482     case GL_SAMPLER_2D:
483     case GL_SAMPLER_2D_SHADOW:
484     case GL_SAMPLER_CUBE: {
485         if (count <= 1) {
486             GLint sampler = *static_cast<const GLint *>(value);
487             GL_CALL_EXTRA_FUNCTION(glProgramUniform1i(programID, GLint(id), sampler));
488         } else {
489             const GLint *sampler = static_cast<const GLint *>(value);
490             GL_CALL_EXTRA_FUNCTION(glProgramUniform1iv(programID, GLint(id), count, sampler));
491         }
492     } break;
493     default:
494         qCCritical(RENDER_INTERNAL_ERROR, "Unknown shader type format %d", int(type));
495         Q_ASSERT(false);
496         break;
497     }
498 }
499 
createComputeShader(QSSGByteView source,QByteArray & errorMessage,bool binary)500 QSSGRenderBackend::QSSGRenderBackendComputeShaderObject QSSGRenderBackendGL4Impl::createComputeShader(QSSGByteView source,
501                                                                                                             QByteArray &errorMessage,
502                                                                                                             bool binary)
503 {
504     GLuint shaderID = 0;
505     shaderID = m_glExtraFunctions->glCreateShader(GL_COMPUTE_SHADER);
506 
507     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
508         GL_CALL_EXTRA_FUNCTION(glDeleteShader(shaderID));
509         shaderID = 0;
510     }
511     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendComputeShaderObject>(quintptr(shaderID));
512 }
513 
dispatchCompute(QSSGRenderBackendShaderProgramObject,quint32 numGroupsX,quint32 numGroupsY,quint32 numGroupsZ)514 void QSSGRenderBackendGL4Impl::dispatchCompute(QSSGRenderBackendShaderProgramObject, quint32 numGroupsX, quint32 numGroupsY, quint32 numGroupsZ)
515 {
516     GL_CALL_EXTRA_FUNCTION(glDispatchCompute(numGroupsX, numGroupsY, numGroupsZ));
517 }
518 
createProgramPipeline()519 QSSGRenderBackend::QSSGRenderBackendProgramPipeline QSSGRenderBackendGL4Impl::createProgramPipeline()
520 {
521     GLuint pipeline;
522     GL_CALL_EXTRA_FUNCTION(glGenProgramPipelines(1, &pipeline));
523 
524     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendProgramPipeline>(quintptr(pipeline));
525 }
526 
releaseProgramPipeline(QSSGRenderBackendProgramPipeline ppo)527 void QSSGRenderBackendGL4Impl::releaseProgramPipeline(QSSGRenderBackendProgramPipeline ppo)
528 {
529     GLuint pipeline = HandleToID_cast(GLuint, quintptr, ppo);
530     GL_CALL_EXTRA_FUNCTION(glDeleteProgramPipelines(1, &pipeline));
531 }
532 
setActiveProgramPipeline(QSSGRenderBackendProgramPipeline ppo)533 void QSSGRenderBackendGL4Impl::setActiveProgramPipeline(QSSGRenderBackendProgramPipeline ppo)
534 {
535     GLuint pipeline = HandleToID_cast(GLuint, quintptr, ppo);
536 
537     GL_CALL_EXTRA_FUNCTION(glBindProgramPipeline(pipeline));
538 }
539 
setProgramStages(QSSGRenderBackendProgramPipeline ppo,QSSGRenderShaderTypeFlags flags,QSSGRenderBackendShaderProgramObject po)540 void QSSGRenderBackendGL4Impl::setProgramStages(QSSGRenderBackendProgramPipeline ppo,
541                                                   QSSGRenderShaderTypeFlags flags,
542                                                   QSSGRenderBackendShaderProgramObject po)
543 {
544     GLuint pipeline = HandleToID_cast(GLuint, quintptr, ppo);
545     GLuint programID = 0;
546 
547     if (po) {
548         QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
549         programID = static_cast<GLuint>(pProgram->m_programID);
550     }
551 
552     GL_CALL_EXTRA_FUNCTION(glUseProgramStages(pipeline, m_conversion.fromShaderTypeFlagsToGL(flags), programID));
553 }
554 
setBlendEquation(const QSSGRenderBlendEquationArgument & pBlendEquArg)555 void QSSGRenderBackendGL4Impl::setBlendEquation(const QSSGRenderBlendEquationArgument &pBlendEquArg)
556 {
557     if (m_backendSupport.caps.bits.bNVAdvancedBlendSupported || m_backendSupport.caps.bits.bKHRAdvancedBlendSupported)
558         GL_CALL_EXTRA_FUNCTION(
559                 glBlendEquation(m_conversion.fromBlendEquationToGL(pBlendEquArg.m_rgbEquation,
560                                                                    m_backendSupport.caps.bits.bNVAdvancedBlendSupported,
561                                                                    m_backendSupport.caps.bits.bKHRAdvancedBlendSupported)));
562 }
563 
setBlendBarrier(void)564 void QSSGRenderBackendGL4Impl::setBlendBarrier(void)
565 {
566     if (m_backendSupport.caps.bits.bNVAdvancedBlendSupported)
567         GL_CALL_QSSG_EXT(glBlendBarrierNV());
568 }
569 
570 QT_END_NAMESPACE
571