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/qssgrenderbackendglbase_p.h>
32 #include <QtQuick3DRender/private/qssgrenderbackendinputassemblergl_p.h>
33 #include <QtQuick3DRender/private/qssgrenderbackendshaderprogramgl_p.h>
34 #include <QtQuick3DRender/private/qssgrenderbackendrenderstatesgl_p.h>
35 
36 QT_BEGIN_NAMESPACE
37 
38 #ifdef RENDER_BACKEND_LOG_GL_ERRORS
39 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError(#x, __FILE__, __LINE__)
40 #else
41 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError()
42 #endif
43 
44 #define GL_CALL_FUNCTION(x)                                                                                            \
45     m_glFunctions->x;                                                                                                  \
46     RENDER_LOG_ERROR_PARAMS(x);
47 #define GL_CALL_EXTRA_FUNCTION(x)                                                                                      \
48     m_glExtraFunctions->x;                                                                                             \
49     RENDER_LOG_ERROR_PARAMS(x);
50 
51 #ifndef GL_PROGRAM_SEPARABLE
52 #define GL_PROGRAM_SEPARABLE 0x8258
53 #endif
54 
55 #ifndef GL_UNSIGNED_INT_IMAGE_2D
56 #define GL_UNSIGNED_INT_IMAGE_2D 0x9063
57 #endif
58 
59 #ifndef GL_UNSIGNED_INT_ATOMIC_COUNTER
60 #define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
61 #endif
62 
63 #ifndef GL_PROGRAM_BINARY_LENGTH
64 #define GL_PROGRAM_BINARY_LENGTH 0x8741
65 #endif
66 
67 namespace QSSGGlExtStrings {
exts3tc()68 QByteArray exts3tc()
69 {
70     return QByteArrayLiteral("GL_EXT_texture_compression_s3tc");
71 }
extsdxt()72 QByteArray extsdxt()
73 {
74     return QByteArrayLiteral("GL_EXT_texture_compression_dxt1");
75 }
extsAniso()76 QByteArray extsAniso()
77 {
78     return QByteArrayLiteral("GL_EXT_texture_filter_anisotropic");
79 }
extsTexSwizzle()80 QByteArray extsTexSwizzle()
81 {
82     return QByteArrayLiteral("GL_ARB_texture_swizzle");
83 }
extsFPRenderTarget()84 QByteArray extsFPRenderTarget()
85 {
86     return QByteArrayLiteral("GL_EXT_color_buffer_float");
87 }
extsTimerQuery()88 QByteArray extsTimerQuery()
89 {
90     return QByteArrayLiteral("GL_EXT_timer_query");
91 }
extsGpuShader5()92 QByteArray extsGpuShader5()
93 {
94     return QByteArrayLiteral("EXT_gpu_shader5");
95 }
96 }
97 
98 /// constructor
QSSGRenderBackendGLBase(const QSurfaceFormat & format)99 QSSGRenderBackendGLBase::QSSGRenderBackendGLBase(const QSurfaceFormat &format)
100     : m_conversion(), m_maxAttribCount(0), m_format(format)
101 {
102     m_glFunctions = new QOpenGLFunctions;
103     m_glFunctions->initializeOpenGLFunctions();
104     m_glExtraFunctions = new QOpenGLExtraFunctions;
105     m_glExtraFunctions->initializeOpenGLFunctions();
106 
107     const QByteArray languageVersion = getShadingLanguageVersionString();
108     qCInfo(RENDER_TRACE_INFO, "GLSL version: %s", languageVersion.constData());
109 
110     const QByteArray apiVersion(getVersionString());
111     qCInfo(RENDER_TRACE_INFO, "GL version: %s", apiVersion.constData());
112 
113     const QByteArray apiVendor(getVendorString());
114     qCInfo(RENDER_TRACE_INFO, "HW vendor: %s", apiVendor.constData());
115 
116     const QByteArray apiRenderer(getRendererString());
117     qCInfo(RENDER_TRACE_INFO, "Vendor renderer: %s", apiRenderer.constData());
118 
119     // internal state tracker
120     m_currentRasterizerState = new QSSGRenderBackendRasterizerStateGL();
121     m_currentDepthStencilState = new QSSGRenderBackendDepthStencilStateGL();
122 }
123 /// destructor
~QSSGRenderBackendGLBase()124 QSSGRenderBackendGLBase::~QSSGRenderBackendGLBase()
125 {
126     delete m_currentRasterizerState;
127     delete m_currentDepthStencilState;
128     delete m_glFunctions;
129     delete m_glExtraFunctions;
130 }
131 
getRenderContextType() const132 QSSGRenderContextType QSSGRenderBackendGLBase::getRenderContextType() const
133 {
134     if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
135         if (m_format.majorVersion() == 2)
136             return QSSGRenderContextType::GLES2;
137 
138         if (m_format.majorVersion() == 3) {
139             if (m_format.minorVersion() >= 1)
140                 return QSSGRenderContextType::GLES3PLUS;
141             return QSSGRenderContextType::GLES3;
142         }
143     } else if (m_format.majorVersion() == 2) {
144         return QSSGRenderContextType::GL2;
145     } else if (m_format.majorVersion() == 3) {
146         return QSSGRenderContextType::GL3;
147     } else if (m_format.majorVersion() == 4) {
148         return QSSGRenderContextType::GL4;
149     }
150 
151     return QSSGRenderContextType::NullContext;
152 }
153 
isESCompatible() const154 bool QSSGRenderBackendGLBase::isESCompatible() const
155 {
156     return m_format.renderableType() == QSurfaceFormat::OpenGLES;
157 }
158 
getShadingLanguageVersion()159 QByteArray QSSGRenderBackendGLBase::getShadingLanguageVersion()
160 {
161     QByteArray ver;
162     QTextStream stream(&ver);
163     stream << "#version ";
164     const int minor = m_format.minorVersion();
165     switch (getRenderContextType()) {
166     case QSSGRenderContextType::GLES2:
167         stream << "1" << minor << "0\n";
168         break;
169     case QSSGRenderContextType::GL2:
170         stream << "1" << minor << "0\n";
171         break;
172     case QSSGRenderContextType::GLES3PLUS:
173     case QSSGRenderContextType::GLES3:
174         stream << "3" << minor << "0 es\n";
175         break;
176     case QSSGRenderContextType::GL3:
177         if (minor == 3)
178             stream << "3" << minor << "0\n";
179         else
180             stream << "1" << 3 + minor << "0\n";
181         break;
182     case QSSGRenderContextType::GL4:
183         stream << "4" << minor << "0\n";
184         break;
185     default:
186         Q_ASSERT(false);
187         break;
188     }
189 
190     return ver;
191 }
192 
getMaxCombinedTextureUnits()193 qint32 QSSGRenderBackendGLBase::getMaxCombinedTextureUnits()
194 {
195     qint32 maxUnits;
196     GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxUnits));
197     return maxUnits;
198 }
199 
getRenderBackendCap(QSSGRenderBackend::QSSGRenderBackendCaps inCap) const200 bool QSSGRenderBackendGLBase::getRenderBackendCap(QSSGRenderBackend::QSSGRenderBackendCaps inCap) const
201 {
202     bool bSupported = false;
203 
204     switch (inCap) {
205     case QSSGRenderBackendCaps::FpRenderTarget:
206         bSupported = m_backendSupport.caps.bits.bFPRenderTargetsSupported;
207         break;
208     case QSSGRenderBackendCaps::DepthStencilTexture:
209         bSupported = m_backendSupport.caps.bits.bDepthStencilSupported;
210         break;
211     case QSSGRenderBackendCaps::ConstantBuffer:
212         bSupported = m_backendSupport.caps.bits.bConstantBufferSupported;
213         break;
214     case QSSGRenderBackendCaps::DxtImages:
215         bSupported = m_backendSupport.caps.bits.bDXTImagesSupported;
216         break;
217     case QSSGRenderBackendCaps::MsTexture:
218         bSupported = m_backendSupport.caps.bits.bMsTextureSupported;
219         break;
220     case QSSGRenderBackendCaps::TexSwizzle:
221         bSupported = m_backendSupport.caps.bits.bTextureSwizzleSupported;
222         break;
223     case QSSGRenderBackendCaps::FastBlits:
224         bSupported = m_backendSupport.caps.bits.bFastBlitsSupported;
225         break;
226     case QSSGRenderBackendCaps::Tessellation:
227         bSupported = m_backendSupport.caps.bits.bTessellationSupported;
228         break;
229     case QSSGRenderBackendCaps::Compute:
230         bSupported = m_backendSupport.caps.bits.bComputeSupported;
231         break;
232     case QSSGRenderBackendCaps::Geometry:
233         bSupported = m_backendSupport.caps.bits.bGeometrySupported;
234         break;
235     case QSSGRenderBackendCaps::SampleQuery: {
236         // On the following context sample query is not supported
237         QSSGRenderContextTypes noSamplesQuerySupportedContextFlags(QSSGRenderContextType::GL2 | QSSGRenderContextType::GLES2);
238         QSSGRenderContextType ctxType = getRenderContextType();
239         bSupported = !(noSamplesQuerySupportedContextFlags & ctxType);
240     } break;
241     case QSSGRenderBackendCaps::TimerQuery:
242         bSupported = m_backendSupport.caps.bits.bTimerQuerySupported;
243         break;
244     case QSSGRenderBackendCaps::CommandSync: {
245         // On the following context sync objects are not supported
246         QSSGRenderContextTypes noSyncObjectSupportedContextFlags(QSSGRenderContextType::GL2 | QSSGRenderContextType::GLES2);
247         QSSGRenderContextType ctxType = getRenderContextType();
248         bSupported = !(noSyncObjectSupportedContextFlags & ctxType);
249     } break;
250     case QSSGRenderBackendCaps::TextureArray: {
251         // On the following context texture arrays are not supported
252         QSSGRenderContextTypes noTextureArraySupportedContextFlags(QSSGRenderContextType::GL2 | QSSGRenderContextType::GLES2);
253         QSSGRenderContextType ctxType = getRenderContextType();
254         bSupported = !(noTextureArraySupportedContextFlags& ctxType);
255     } break;
256     case QSSGRenderBackendCaps::StorageBuffer:
257         bSupported = m_backendSupport.caps.bits.bStorageBufferSupported;
258         break;
259     case QSSGRenderBackendCaps::ShaderImageLoadStore:
260         bSupported = m_backendSupport.caps.bits.bShaderImageLoadStoreSupported;
261         break;
262     case QSSGRenderBackendCaps::ProgramPipeline:
263         bSupported = m_backendSupport.caps.bits.bProgramPipelineSupported;
264         break;
265     case QSSGRenderBackendCaps::AdvancedBlend:
266         bSupported = m_backendSupport.caps.bits.bNVAdvancedBlendSupported | m_backendSupport.caps.bits.bKHRAdvancedBlendSupported;
267         break;
268     case QSSGRenderBackendCaps::AdvancedBlendKHR:
269         bSupported = m_backendSupport.caps.bits.bKHRAdvancedBlendSupported;
270         break;
271     case QSSGRenderBackendCaps::BlendCoherency:
272         bSupported = m_backendSupport.caps.bits.bNVBlendCoherenceSupported | m_backendSupport.caps.bits.bKHRBlendCoherenceSupported;
273         break;
274     case QSSGRenderBackendCaps::gpuShader5:
275         bSupported = m_backendSupport.caps.bits.bGPUShader5ExtensionSupported;
276         break;
277     case QSSGRenderBackendCaps::VertexArrayObject:
278         bSupported = m_backendSupport.caps.bits.bVertexArrayObjectSupported;
279         break;
280     case QSSGRenderBackendCaps::StandardDerivatives:
281         bSupported = m_backendSupport.caps.bits.bStandardDerivativesSupported;
282         break;
283     case QSSGRenderBackendCaps::TextureLod:
284         bSupported = m_backendSupport.caps.bits.bTextureLodSupported;
285         break;
286     default:
287         Q_ASSERT(false);
288         bSupported = false;
289         break;
290     }
291 
292     return bSupported;
293 }
294 
getRenderBackendValue(QSSGRenderBackendQuery inQuery,qint32 * params) const295 void QSSGRenderBackendGLBase::getRenderBackendValue(QSSGRenderBackendQuery inQuery, qint32 *params) const
296 {
297     if (params) {
298         switch (inQuery) {
299         case QSSGRenderBackendQuery::MaxTextureSize:
300             GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_TEXTURE_SIZE, params));
301             break;
302         case QSSGRenderBackendQuery::MaxTextureArrayLayers: {
303             QSSGRenderContextTypes noTextureArraySupportedContextFlags(QSSGRenderContextType::GL2
304                                                                         | QSSGRenderContextType::GLES2);
305             QSSGRenderContextType ctxType = getRenderContextType();
306             if (!(noTextureArraySupportedContextFlags & ctxType)) {
307                 GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, params));
308             } else {
309                 *params = 0;
310             }
311         } break;
312         case QSSGRenderBackendQuery::MaxConstantBufferSlots: {
313             QSSGRenderContextTypes noConstantBufferSupportedContextFlags(QSSGRenderContextType::GL2
314                                                                           | QSSGRenderContextType::GLES2);
315             QSSGRenderContextType ctxType = getRenderContextType();
316             if (!(noConstantBufferSupportedContextFlags & ctxType)) {
317                 GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, params));
318             } else {
319                 *params = 0;
320             }
321         } break;
322         case QSSGRenderBackendQuery::MaxConstantBufferBlockSize: {
323             QSSGRenderContextTypes noConstantBufferSupportedContextFlags(QSSGRenderContextType::GL2
324                                                                           | QSSGRenderContextType::GLES2);
325             QSSGRenderContextType ctxType = getRenderContextType();
326             if (!(noConstantBufferSupportedContextFlags & ctxType)) {
327                 GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, params));
328             } else {
329                 *params = 0;
330             }
331         } break;
332         default:
333             Q_ASSERT(false);
334             *params = 0;
335             break;
336         }
337     }
338 }
339 
getDepthBits() const340 qint32 QSSGRenderBackendGLBase::getDepthBits() const
341 {
342     qint32 depthBits;
343     GL_CALL_FUNCTION(glGetIntegerv(GL_DEPTH_BITS, &depthBits));
344     return depthBits;
345 }
346 
getStencilBits() const347 qint32 QSSGRenderBackendGLBase::getStencilBits() const
348 {
349     qint32 stencilBits;
350     GL_CALL_FUNCTION(glGetIntegerv(GL_STENCIL_BITS, &stencilBits));
351     return stencilBits;
352 }
353 
getMaxSamples() const354 qint32 QSSGRenderBackendGLBase::getMaxSamples() const
355 {
356     qint32 maxSamples;
357     GL_CALL_FUNCTION(glGetIntegerv(GL_MAX_SAMPLES, &maxSamples));
358     return maxSamples;
359 }
360 
setMultisample(bool bEnable)361 void QSSGRenderBackendGLBase::setMultisample(bool bEnable)
362 {
363     Q_ASSERT(m_backendSupport.caps.bits.bMsTextureSupported || !bEnable);
364     // For GL ES explicit multisample enabling is not needed
365     // and does not exist
366     QSSGRenderContextTypes noMsaaEnableContextFlags(QSSGRenderContextType::GLES2 | QSSGRenderContextType::GLES3
367                                                      | QSSGRenderContextType::GLES3PLUS);
368     QSSGRenderContextType ctxType = getRenderContextType();
369     if (!(noMsaaEnableContextFlags & ctxType)) {
370         setRenderState(bEnable, QSSGRenderState::Multisample);
371     }
372 }
373 
setRenderState(bool bEnable,const QSSGRenderState value)374 void QSSGRenderBackendGLBase::setRenderState(bool bEnable, const QSSGRenderState value)
375 {
376     if (value == QSSGRenderState::DepthWrite) {
377         GL_CALL_FUNCTION(glDepthMask(bEnable));
378     } else {
379         if (bEnable) {
380             GL_CALL_FUNCTION(glEnable(m_conversion.fromRenderStateToGL(value)));
381         } else {
382             GL_CALL_FUNCTION(glDisable(m_conversion.fromRenderStateToGL(value)));
383         }
384     }
385 }
386 
createDepthStencilState(bool enableDepth,bool depthMask,QSSGRenderBoolOp depthFunc,bool enableStencil,QSSGRenderStencilFunction & stencilFuncFront,QSSGRenderStencilFunction & stencilFuncBack,QSSGRenderStencilOperation & depthStencilOpFront,QSSGRenderStencilOperation & depthStencilOpBack)387 QSSGRenderBackend::QSSGRenderBackendDepthStencilStateObject QSSGRenderBackendGLBase::createDepthStencilState(
388         bool enableDepth,
389         bool depthMask,
390         QSSGRenderBoolOp depthFunc,
391         bool enableStencil,
392         QSSGRenderStencilFunction &stencilFuncFront,
393         QSSGRenderStencilFunction &stencilFuncBack,
394         QSSGRenderStencilOperation &depthStencilOpFront,
395         QSSGRenderStencilOperation &depthStencilOpBack)
396 {
397     QSSGRenderBackendDepthStencilStateGL *retval = new QSSGRenderBackendDepthStencilStateGL(enableDepth,
398                                                                                                 depthMask,
399                                                                                                 depthFunc,
400                                                                                                 enableStencil,
401                                                                                                 stencilFuncFront,
402                                                                                                 stencilFuncBack,
403                                                                                                 depthStencilOpFront,
404                                                                                                 depthStencilOpBack);
405 
406     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendDepthStencilStateObject>(retval);
407 }
408 
releaseDepthStencilState(QSSGRenderBackendDepthStencilStateObject inDepthStencilState)409 void QSSGRenderBackendGLBase::releaseDepthStencilState(QSSGRenderBackendDepthStencilStateObject inDepthStencilState)
410 {
411     QSSGRenderBackendDepthStencilStateGL *inputState = reinterpret_cast<QSSGRenderBackendDepthStencilStateGL *>(inDepthStencilState);
412     delete inputState;
413 }
414 
createRasterizerState(float depthBias,float depthScale)415 QSSGRenderBackend::QSSGRenderBackendRasterizerStateObject QSSGRenderBackendGLBase::createRasterizerState(float depthBias,
416                                                                                                          float depthScale)
417 {
418     QSSGRenderBackendRasterizerStateGL *retval = new QSSGRenderBackendRasterizerStateGL(depthBias, depthScale);
419 
420     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendRasterizerStateObject>(retval);
421 }
422 
releaseRasterizerState(QSSGRenderBackendRasterizerStateObject rasterizerState)423 void QSSGRenderBackendGLBase::releaseRasterizerState(QSSGRenderBackendRasterizerStateObject rasterizerState)
424 {
425     delete reinterpret_cast<QSSGRenderBackendRasterizerStateGL *>(rasterizerState);
426 }
427 
setDepthStencilState(QSSGRenderBackendDepthStencilStateObject inDepthStencilState)428 void QSSGRenderBackendGLBase::setDepthStencilState(QSSGRenderBackendDepthStencilStateObject inDepthStencilState)
429 {
430     QSSGRenderBackendDepthStencilStateGL *inputState = reinterpret_cast<QSSGRenderBackendDepthStencilStateGL *>(inDepthStencilState);
431     if (inputState && !(*m_currentDepthStencilState == *inputState)) {
432         // we check on a per single state base
433         if (inputState->m_depthEnable != m_currentDepthStencilState->m_depthEnable) {
434             setRenderState(inputState->m_depthEnable, QSSGRenderState::DepthTest);
435             m_currentDepthStencilState->m_depthEnable = inputState->m_depthEnable;
436         }
437         if (inputState->m_stencilEnable != m_currentDepthStencilState->m_stencilEnable) {
438             setRenderState(inputState->m_stencilEnable, QSSGRenderState::StencilTest);
439             m_currentDepthStencilState->m_stencilEnable = inputState->m_stencilEnable;
440         }
441 
442         if (inputState->m_depthMask != m_currentDepthStencilState->m_depthMask) {
443             GL_CALL_FUNCTION(glDepthMask(inputState->m_depthMask));
444             m_currentDepthStencilState->m_depthMask = inputState->m_depthMask;
445         }
446 
447         if (inputState->m_depthFunc != m_currentDepthStencilState->m_depthFunc) {
448             GL_CALL_FUNCTION(glDepthFunc(m_conversion.fromBoolOpToGL(inputState->m_depthFunc)));
449             m_currentDepthStencilState->m_depthFunc = inputState->m_depthFunc;
450         }
451 
452         if (!(inputState->m_depthStencilOpFront == m_currentDepthStencilState->m_depthStencilOpFront)) {
453             GL_CALL_FUNCTION(
454                     glStencilOpSeparate(GL_FRONT,
455                                         m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpFront.m_stencilFail),
456                                         m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpFront.m_depthFail),
457                                         m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpFront.m_depthPass)));
458             m_currentDepthStencilState->m_depthStencilOpFront = inputState->m_depthStencilOpFront;
459         }
460 
461         if (!(inputState->m_depthStencilOpBack == m_currentDepthStencilState->m_depthStencilOpBack)) {
462             GL_CALL_FUNCTION(glStencilOpSeparate(GL_BACK,
463                                                  m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpBack.m_stencilFail),
464                                                  m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpBack.m_depthFail),
465                                                  m_conversion.fromStencilOpToGL(inputState->m_depthStencilOpBack.m_depthPass)));
466             m_currentDepthStencilState->m_depthStencilOpBack = inputState->m_depthStencilOpBack;
467         }
468 
469         if (!(inputState->m_stencilFuncFront == m_currentDepthStencilState->m_stencilFuncFront)) {
470             GL_CALL_FUNCTION(glStencilFuncSeparate(GL_FRONT,
471                                                    m_conversion.fromBoolOpToGL(inputState->m_stencilFuncFront.m_function),
472                                                    inputState->m_stencilFuncFront.m_referenceValue,
473                                                    inputState->m_stencilFuncFront.m_mask));
474             m_currentDepthStencilState->m_stencilFuncFront = inputState->m_stencilFuncFront;
475         }
476 
477         if (!(inputState->m_stencilFuncBack == m_currentDepthStencilState->m_stencilFuncBack)) {
478             GL_CALL_FUNCTION(glStencilFuncSeparate(GL_BACK,
479                                                    m_conversion.fromBoolOpToGL(inputState->m_stencilFuncBack.m_function),
480                                                    inputState->m_stencilFuncBack.m_referenceValue,
481                                                    inputState->m_stencilFuncBack.m_mask));
482             m_currentDepthStencilState->m_stencilFuncBack = inputState->m_stencilFuncBack;
483         }
484     }
485 }
486 
setRasterizerState(QSSGRenderBackendRasterizerStateObject rasterizerState)487 void QSSGRenderBackendGLBase::setRasterizerState(QSSGRenderBackendRasterizerStateObject rasterizerState)
488 {
489     QSSGRenderBackendRasterizerStateGL *inputState = (QSSGRenderBackendRasterizerStateGL *)rasterizerState;
490     if (inputState && !(*m_currentRasterizerState == *inputState)) {
491         // store current state
492         *m_currentRasterizerState = *inputState;
493 
494         if (m_currentRasterizerState->m_depthBias != 0.0f || m_currentRasterizerState->m_depthScale != 0.0f) {
495             GL_CALL_FUNCTION(glEnable(GL_POLYGON_OFFSET_FILL));
496         } else {
497             GL_CALL_FUNCTION(glDisable(GL_POLYGON_OFFSET_FILL));
498         }
499 
500         GL_CALL_FUNCTION(glPolygonOffset(m_currentRasterizerState->m_depthBias, m_currentRasterizerState->m_depthScale));
501     }
502 }
503 
getRenderState(const QSSGRenderState value)504 bool QSSGRenderBackendGLBase::getRenderState(const QSSGRenderState value)
505 {
506     bool enabled = GL_CALL_FUNCTION(glIsEnabled(m_conversion.fromRenderStateToGL(value)));
507     return enabled;
508 }
509 
getDepthFunc()510 QSSGRenderBoolOp QSSGRenderBackendGLBase::getDepthFunc()
511 {
512     qint32 value;
513     GL_CALL_FUNCTION(glGetIntegerv(GL_DEPTH_FUNC, &value));
514     return GLConversion::fromGLToBoolOp(value);
515 }
516 
setDepthFunc(const QSSGRenderBoolOp func)517 void QSSGRenderBackendGLBase::setDepthFunc(const QSSGRenderBoolOp func)
518 {
519     GL_CALL_FUNCTION(glDepthFunc(m_conversion.fromBoolOpToGL(func)));
520 }
521 
getDepthWrite()522 bool QSSGRenderBackendGLBase::getDepthWrite()
523 {
524     qint32 value;
525     GL_CALL_FUNCTION(glGetIntegerv(GL_DEPTH_WRITEMASK, reinterpret_cast<GLint *>(&value)));
526     return (value != 0);
527 }
528 
setDepthWrite(bool bEnable)529 void QSSGRenderBackendGLBase::setDepthWrite(bool bEnable)
530 {
531     GL_CALL_FUNCTION(glDepthMask(bEnable));
532 }
533 
setColorWrites(bool bRed,bool bGreen,bool bBlue,bool bAlpha)534 void QSSGRenderBackendGLBase::setColorWrites(bool bRed, bool bGreen, bool bBlue, bool bAlpha)
535 {
536     GL_CALL_FUNCTION(glColorMask(bRed, bGreen, bBlue, bAlpha));
537 }
538 
getBlendFunc(QSSGRenderBlendFunctionArgument * pBlendFuncArg)539 void QSSGRenderBackendGLBase::getBlendFunc(QSSGRenderBlendFunctionArgument *pBlendFuncArg)
540 {
541     Q_ASSERT(pBlendFuncArg);
542     qint32_4 values;
543 
544     GL_CALL_FUNCTION(glGetIntegerv(GL_BLEND_SRC_RGB, reinterpret_cast<GLint *>(&values.x)));
545     GL_CALL_FUNCTION(glGetIntegerv(GL_BLEND_SRC_ALPHA, reinterpret_cast<GLint *>(&values.y)));
546     GL_CALL_FUNCTION(glGetIntegerv(GL_BLEND_DST_RGB, reinterpret_cast<GLint *>(&values.z)));
547     GL_CALL_FUNCTION(glGetIntegerv(GL_BLEND_DST_ALPHA, reinterpret_cast<GLint *>(&values.w)));
548 
549     pBlendFuncArg->m_srcRgb = GLConversion::fromGLToSrcBlendFunc(values.x);
550     pBlendFuncArg->m_srcAlpha = GLConversion::fromGLToSrcBlendFunc(values.y);
551     pBlendFuncArg->m_dstRgb = GLConversion::fromGLToDstBlendFunc(values.z);
552     pBlendFuncArg->m_dstAlpha = GLConversion::fromGLToDstBlendFunc(values.w);
553 }
554 
setBlendFunc(const QSSGRenderBlendFunctionArgument & blendFuncArg)555 void QSSGRenderBackendGLBase::setBlendFunc(const QSSGRenderBlendFunctionArgument &blendFuncArg)
556 {
557     qint32_4 values;
558 
559     values.x = GLConversion::fromSrcBlendFuncToGL(blendFuncArg.m_srcRgb);
560     values.y = GLConversion::fromDstBlendFuncToGL(blendFuncArg.m_dstRgb);
561     values.z = GLConversion::fromSrcBlendFuncToGL(blendFuncArg.m_srcAlpha);
562     values.w = GLConversion::fromDstBlendFuncToGL(blendFuncArg.m_dstAlpha);
563 
564     GL_CALL_FUNCTION(glBlendFuncSeparate(values.x, values.y, values.z, values.w));
565 }
566 
setBlendEquation(const QSSGRenderBlendEquationArgument &)567 void QSSGRenderBackendGLBase::setBlendEquation(const QSSGRenderBlendEquationArgument &)
568 {
569     // needs GL4 / GLES 3.1
570     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
571 }
572 
setBlendBarrier()573 void QSSGRenderBackendGLBase::setBlendBarrier()
574 {
575     // needs GL4 / GLES 3.1
576     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
577 }
578 
getCullFaceMode()579 QSSGCullFaceMode QSSGRenderBackendGLBase::getCullFaceMode()
580 {
581     GLint value;
582     GL_CALL_FUNCTION(glGetIntegerv(GL_CULL_FACE_MODE, &value));
583     return GLConversion::fromGLToCullFaceMode(static_cast<GLenum>(value));
584 }
585 
setCullFaceMode(const QSSGCullFaceMode cullFaceMode)586 void QSSGRenderBackendGLBase::setCullFaceMode(const QSSGCullFaceMode cullFaceMode)
587 {
588     GL_CALL_FUNCTION(glCullFace(GLConversion::fromCullFaceModeToGL(cullFaceMode)));
589 }
590 
getScissorRect(QRect * pRect)591 void QSSGRenderBackendGLBase::getScissorRect(QRect *pRect)
592 {
593     Q_ASSERT(pRect);
594     GL_CALL_FUNCTION(glGetIntegerv(GL_SCISSOR_BOX, reinterpret_cast<GLint *>(pRect)));
595 }
596 
setScissorRect(const QRect & rect)597 void QSSGRenderBackendGLBase::setScissorRect(const QRect &rect)
598 {
599     GL_CALL_FUNCTION(glScissor(rect.x(), rect.y(), rect.width(), rect.height()));
600 }
601 
getViewportRect(QRect * pRect)602 void QSSGRenderBackendGLBase::getViewportRect(QRect *pRect)
603 {
604     Q_ASSERT(pRect);
605     GL_CALL_FUNCTION(glGetIntegerv(GL_VIEWPORT, reinterpret_cast<GLint *>(pRect)));
606 }
607 
setViewportRect(const QRect & rect)608 void QSSGRenderBackendGLBase::setViewportRect(const QRect &rect)
609 {
610     GL_CALL_FUNCTION(glViewport(rect.x(), rect.y(), rect.width(), rect.height()););
611 }
612 
setClearColor(const QVector4D * pClearColor)613 void QSSGRenderBackendGLBase::setClearColor(const QVector4D *pClearColor)
614 {
615     Q_ASSERT(pClearColor);
616 
617     GL_CALL_FUNCTION(glClearColor(pClearColor->x(), pClearColor->y(), pClearColor->z(), pClearColor->w()));
618 }
619 
clear(QSSGRenderClearFlags flags)620 void QSSGRenderBackendGLBase::clear(QSSGRenderClearFlags flags)
621 {
622     GL_CALL_FUNCTION(glClear(m_conversion.fromClearFlagsToGL(flags)));
623 }
624 
createBuffer(QSSGRenderBufferType bindFlags,QSSGRenderBufferUsageType usage,QSSGByteView hostData)625 QSSGRenderBackend::QSSGRenderBackendBufferObject QSSGRenderBackendGLBase::createBuffer(QSSGRenderBufferType bindFlags,
626                                                                                              QSSGRenderBufferUsageType usage,
627                                                                                              QSSGByteView hostData)
628 {
629     GLuint bufID = 0;
630 
631     GL_CALL_FUNCTION(glGenBuffers(1, &bufID));
632 
633     if (bufID && hostData.size()) {
634         GLenum target = GLConversion::fromBindBufferFlagsToGL(bindFlags);
635         if (target != GL_INVALID_ENUM) {
636             GL_CALL_FUNCTION(glBindBuffer(target, bufID));
637             GL_CALL_FUNCTION(glBufferData(target, hostData.size(), hostData, m_conversion.fromBufferUsageTypeToGL(usage)));
638         } else {
639             GL_CALL_FUNCTION(glDeleteBuffers(1, &bufID));
640             bufID = 0;
641             qCCritical(RENDER_GL_ERROR, "%s", GLConversion::processGLError(target));
642         }
643     }
644 
645     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendBufferObject>(quintptr(bufID));
646 }
647 
bindBuffer(QSSGRenderBackendBufferObject bo,QSSGRenderBufferType bindFlags)648 void QSSGRenderBackendGLBase::bindBuffer(QSSGRenderBackendBufferObject bo, QSSGRenderBufferType bindFlags)
649 {
650     GLuint bufID = HandleToID_cast(GLuint, quintptr, bo);
651     GL_CALL_FUNCTION(glBindBuffer(m_conversion.fromBindBufferFlagsToGL(bindFlags), bufID));
652 }
653 
releaseBuffer(QSSGRenderBackendBufferObject bo)654 void QSSGRenderBackendGLBase::releaseBuffer(QSSGRenderBackendBufferObject bo)
655 {
656     GLuint bufID = HandleToID_cast(GLuint, quintptr, bo);
657     GL_CALL_FUNCTION(glDeleteBuffers(1, &bufID));
658 }
659 
updateBuffer(QSSGRenderBackendBufferObject bo,QSSGRenderBufferType bindFlags,QSSGRenderBufferUsageType usage,QSSGByteView data)660 void QSSGRenderBackendGLBase::updateBuffer(QSSGRenderBackendBufferObject bo,
661                                              QSSGRenderBufferType bindFlags,
662                                              QSSGRenderBufferUsageType usage,
663                                              QSSGByteView data)
664 {
665     GLuint bufID = HandleToID_cast(GLuint, quintptr, bo);
666     GLenum target = GLConversion::fromBindBufferFlagsToGL(bindFlags);
667     GL_CALL_FUNCTION(glBindBuffer(target, bufID));
668     GL_CALL_FUNCTION(glBufferData(target, data.size(), data, m_conversion.fromBufferUsageTypeToGL(usage)));
669 }
670 
updateBufferRange(QSSGRenderBackendBufferObject bo,QSSGRenderBufferType bindFlags,size_t offset,QSSGByteView data)671 void QSSGRenderBackendGLBase::updateBufferRange(QSSGRenderBackendBufferObject bo,
672                                                   QSSGRenderBufferType bindFlags,
673                                                   size_t offset,
674                                                   QSSGByteView data)
675 {
676     GLuint bufID = HandleToID_cast(GLuint, quintptr, bo);
677     GLenum target = GLConversion::fromBindBufferFlagsToGL(bindFlags);
678     GL_CALL_FUNCTION(glBindBuffer(target, bufID));
679     GL_CALL_FUNCTION(glBufferSubData(target, offset, data.size(), data));
680 }
681 
mapBuffer(QSSGRenderBackendBufferObject,QSSGRenderBufferType,size_t,size_t,QSSGRenderBufferAccessFlags)682 void *QSSGRenderBackendGLBase::mapBuffer(QSSGRenderBackendBufferObject, QSSGRenderBufferType, size_t, size_t, QSSGRenderBufferAccessFlags)
683 {
684     // needs GL 3 context
685     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
686 
687     return nullptr;
688 }
689 
unmapBuffer(QSSGRenderBackendBufferObject,QSSGRenderBufferType)690 bool QSSGRenderBackendGLBase::unmapBuffer(QSSGRenderBackendBufferObject, QSSGRenderBufferType)
691 {
692     // needs GL 3 context
693     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
694 
695     return true;
696 }
697 
setMemoryBarrier(QSSGRenderBufferBarrierFlags)698 void QSSGRenderBackendGLBase::setMemoryBarrier(QSSGRenderBufferBarrierFlags)
699 {
700     // needs GL 4 context
701     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
702 }
703 
createQuery()704 QSSGRenderBackend::QSSGRenderBackendQueryObject QSSGRenderBackendGLBase::createQuery()
705 {
706     // needs GL 3 context
707     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
708 
709     return QSSGRenderBackendQueryObject(nullptr);
710 }
711 
releaseQuery(QSSGRenderBackendQueryObject)712 void QSSGRenderBackendGLBase::releaseQuery(QSSGRenderBackendQueryObject)
713 {
714     // needs GL 3 context
715     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
716 }
717 
beginQuery(QSSGRenderBackendQueryObject,QSSGRenderQueryType)718 void QSSGRenderBackendGLBase::beginQuery(QSSGRenderBackendQueryObject, QSSGRenderQueryType)
719 {
720     // needs GL 3 context
721     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
722 }
723 
endQuery(QSSGRenderBackendQueryObject,QSSGRenderQueryType)724 void QSSGRenderBackendGLBase::endQuery(QSSGRenderBackendQueryObject, QSSGRenderQueryType)
725 {
726     // needs GL 3 context
727     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
728 }
729 
getQueryResult(QSSGRenderBackendQueryObject,QSSGRenderQueryResultType,quint32 *)730 void QSSGRenderBackendGLBase::getQueryResult(QSSGRenderBackendQueryObject, QSSGRenderQueryResultType, quint32 *)
731 {
732     // needs GL 3 context
733     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
734 }
735 
getQueryResult(QSSGRenderBackendQueryObject,QSSGRenderQueryResultType,quint64 *)736 void QSSGRenderBackendGLBase::getQueryResult(QSSGRenderBackendQueryObject, QSSGRenderQueryResultType, quint64 *)
737 {
738     // needs GL 3 context
739     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
740 }
741 
setQueryTimer(QSSGRenderBackendQueryObject)742 void QSSGRenderBackendGLBase::setQueryTimer(QSSGRenderBackendQueryObject)
743 {
744     // needs GL 3 context
745     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
746 }
747 
createSync(QSSGRenderSyncType,QSSGRenderSyncFlags)748 QSSGRenderBackend::QSSGRenderBackendSyncObject QSSGRenderBackendGLBase::createSync(QSSGRenderSyncType, QSSGRenderSyncFlags)
749 {
750     // needs GL 3 context
751     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
752 
753     return QSSGRenderBackendSyncObject(nullptr);
754 }
755 
releaseSync(QSSGRenderBackendSyncObject)756 void QSSGRenderBackendGLBase::releaseSync(QSSGRenderBackendSyncObject)
757 {
758     // needs GL 3 context
759     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
760 }
761 
waitSync(QSSGRenderBackendSyncObject,QSSGRenderCommandFlushFlags,quint64)762 void QSSGRenderBackendGLBase::waitSync(QSSGRenderBackendSyncObject, QSSGRenderCommandFlushFlags, quint64)
763 {
764     // needs GL 3 context
765     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
766 }
767 
createRenderTarget()768 QSSGRenderBackend::QSSGRenderBackendRenderTargetObject QSSGRenderBackendGLBase::createRenderTarget()
769 {
770     GLuint fboID = 0;
771 
772     GL_CALL_FUNCTION(glGenFramebuffers(1, &fboID));
773 
774     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendRenderTargetObject>(quintptr(fboID));
775 }
776 
releaseRenderTarget(QSSGRenderBackendRenderTargetObject rto)777 void QSSGRenderBackendGLBase::releaseRenderTarget(QSSGRenderBackendRenderTargetObject rto)
778 {
779     GLuint fboID = HandleToID_cast(GLuint, quintptr, rto);
780 
781     if (fboID) {
782         GL_CALL_FUNCTION(glDeleteFramebuffers(1, &fboID));
783     }
784 }
785 
renderTargetAttach(QSSGRenderBackendRenderTargetObject,QSSGRenderFrameBufferAttachment attachment,QSSGRenderBackendRenderbufferObject rbo)786 void QSSGRenderBackendGLBase::renderTargetAttach(QSSGRenderBackendRenderTargetObject /* rto */,
787                                                    QSSGRenderFrameBufferAttachment attachment,
788                                                    QSSGRenderBackendRenderbufferObject rbo)
789 {
790     // rto must be the current render target
791     GLuint rbID = HandleToID_cast(GLuint, quintptr, rbo);
792 
793     GLenum glAttach = GLConversion::fromFramebufferAttachmentsToGL(attachment);
794 
795     GL_CALL_FUNCTION(glFramebufferRenderbuffer(GL_FRAMEBUFFER, glAttach, GL_RENDERBUFFER, rbID));
796 }
797 
renderTargetAttach(QSSGRenderBackendRenderTargetObject,QSSGRenderFrameBufferAttachment attachment,QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target)798 void QSSGRenderBackendGLBase::renderTargetAttach(QSSGRenderBackendRenderTargetObject /* rto */,
799                                                    QSSGRenderFrameBufferAttachment attachment,
800                                                    QSSGRenderBackendTextureObject to,
801                                                    QSSGRenderTextureTargetType target)
802 {
803     // rto must be the current render target
804     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
805 
806     Q_ASSERT(target == QSSGRenderTextureTargetType::Texture2D || m_backendSupport.caps.bits.bMsTextureSupported);
807 
808     GLenum glAttach = GLConversion::fromFramebufferAttachmentsToGL(attachment);
809     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
810 
811     GL_CALL_FUNCTION(glFramebufferTexture2D(GL_FRAMEBUFFER, glAttach, glTarget, texID, 0))
812 }
813 
renderTargetAttach(QSSGRenderBackendRenderTargetObject,QSSGRenderFrameBufferAttachment,QSSGRenderBackendTextureObject,qint32,qint32)814 void QSSGRenderBackendGLBase::renderTargetAttach(QSSGRenderBackendRenderTargetObject,
815                                                    QSSGRenderFrameBufferAttachment,
816                                                    QSSGRenderBackendTextureObject,
817                                                    qint32,
818                                                    qint32)
819 {
820     // Needs GL3 or GLES 3
821     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
822 }
823 
setRenderTarget(QSSGRenderBackendRenderTargetObject rto)824 void QSSGRenderBackendGLBase::setRenderTarget(QSSGRenderBackendRenderTargetObject rto)
825 {
826     GLuint fboID = HandleToID_cast(GLuint, quintptr, rto);
827 
828     GL_CALL_FUNCTION(glBindFramebuffer(GL_FRAMEBUFFER, fboID));
829 }
830 
renderTargetIsValid(QSSGRenderBackendRenderTargetObject)831 bool QSSGRenderBackendGLBase::renderTargetIsValid(QSSGRenderBackendRenderTargetObject /* rto */)
832 {
833     // rto must be the current render target
834     GLenum completeStatus = GL_CALL_FUNCTION(glCheckFramebufferStatus(GL_FRAMEBUFFER));
835     switch (completeStatus) {
836 #define HANDLE_INCOMPLETE_STATUS(x)                                                                                    \
837     case x:                                                                                                            \
838         qCCritical(RENDER_INTERNAL_ERROR, "Framebuffer is not complete: %s", #x);                                             \
839         return false;
840         HANDLE_INCOMPLETE_STATUS(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
841         HANDLE_INCOMPLETE_STATUS(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS)
842         HANDLE_INCOMPLETE_STATUS(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
843         HANDLE_INCOMPLETE_STATUS(GL_FRAMEBUFFER_UNSUPPORTED)
844 #undef HANDLE_INCOMPLETE_STATUS
845     }
846     return true;
847 }
848 
createRenderbuffer(QSSGRenderRenderBufferFormat storageFormat,qint32 width,qint32 height)849 QSSGRenderBackend::QSSGRenderBackendRenderbufferObject QSSGRenderBackendGLBase::createRenderbuffer(QSSGRenderRenderBufferFormat storageFormat,
850                                                                                                          qint32 width,
851                                                                                                          qint32 height)
852 {
853     GLuint bufID = 0;
854 
855     GL_CALL_FUNCTION(glGenRenderbuffers(1, &bufID));
856     GL_CALL_FUNCTION(glBindRenderbuffer(GL_RENDERBUFFER, bufID));
857     GL_CALL_FUNCTION(glRenderbufferStorage(GL_RENDERBUFFER,
858                                            GLConversion::fromRenderBufferFormatsToRenderBufferGL(storageFormat),
859                                            GLsizei(width),
860                                            GLsizei(height)));
861 
862     // check for error
863     GLenum error = m_glFunctions->glGetError();
864     if (error != GL_NO_ERROR) {
865         qCCritical(RENDER_GL_ERROR, "%s", GLConversion::processGLError(error));
866         Q_ASSERT(false);
867         GL_CALL_FUNCTION(glDeleteRenderbuffers(1, &bufID));
868         bufID = 0;
869     }
870 
871     GL_CALL_FUNCTION(glBindRenderbuffer(GL_RENDERBUFFER, 0));
872 
873     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendRenderbufferObject>(quintptr(bufID));
874 }
875 
releaseRenderbuffer(QSSGRenderBackendRenderbufferObject rbo)876 void QSSGRenderBackendGLBase::releaseRenderbuffer(QSSGRenderBackendRenderbufferObject rbo)
877 {
878     GLuint bufID = HandleToID_cast(GLuint, quintptr, rbo);
879 
880     if (bufID) {
881         GL_CALL_FUNCTION(glDeleteRenderbuffers(1, &bufID));
882     }
883 }
884 
resizeRenderbuffer(QSSGRenderBackendRenderbufferObject rbo,QSSGRenderRenderBufferFormat storageFormat,qint32 width,qint32 height)885 bool QSSGRenderBackendGLBase::resizeRenderbuffer(QSSGRenderBackendRenderbufferObject rbo,
886                                                    QSSGRenderRenderBufferFormat storageFormat,
887                                                    qint32 width,
888                                                    qint32 height)
889 {
890     bool success = true;
891     GLuint bufID = HandleToID_cast(GLuint, quintptr, rbo);
892 
893     Q_ASSERT(bufID);
894 
895     GL_CALL_FUNCTION(glBindRenderbuffer(GL_RENDERBUFFER, bufID));
896     GL_CALL_FUNCTION(glRenderbufferStorage(GL_RENDERBUFFER,
897                                            GLConversion::fromRenderBufferFormatsToRenderBufferGL(storageFormat),
898                                            GLsizei(width),
899                                            GLsizei(height)));
900 
901     // check for error
902     GLenum error = m_glFunctions->glGetError();
903     if (error != GL_NO_ERROR) {
904         qCCritical(RENDER_GL_ERROR, "%s", GLConversion::processGLError(error));
905         Q_ASSERT(false);
906         success = false;
907     }
908 
909     return success;
910 }
911 
createTexture()912 QSSGRenderBackend::QSSGRenderBackendTextureObject QSSGRenderBackendGLBase::createTexture()
913 {
914     GLuint texID = 0;
915 
916     GL_CALL_FUNCTION(glGenTextures(1, &texID));
917     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendTextureObject>(quintptr(texID));
918 }
919 
bindTexture(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 unit)920 void QSSGRenderBackendGLBase::bindTexture(QSSGRenderBackendTextureObject to,
921                                             QSSGRenderTextureTargetType target,
922                                             qint32 unit)
923 {
924     Q_ASSERT(unit >= 0);
925     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
926     setActiveTexture(GL_TEXTURE0 + GLenum(unit));
927 
928     GL_CALL_FUNCTION(glBindTexture(m_conversion.fromTextureTargetToGL(target), texID));
929 }
930 
setActiveTexture(qint32 unit)931 void QSSGRenderBackendGLBase::setActiveTexture(qint32 unit)
932 {
933     if (unit != m_activatedTextureUnit) {
934         GL_CALL_FUNCTION(glActiveTexture(GLenum(unit)))
935         m_activatedTextureUnit = unit;
936     }
937 }
938 
bindImageTexture(QSSGRenderBackendTextureObject,quint32,qint32,bool,qint32,QSSGRenderImageAccessType,QSSGRenderTextureFormat)939 void QSSGRenderBackendGLBase::bindImageTexture(QSSGRenderBackendTextureObject,
940                                                  quint32,
941                                                  qint32,
942                                                  bool,
943                                                  qint32,
944                                                  QSSGRenderImageAccessType,
945                                                  QSSGRenderTextureFormat)
946 {
947     // needs GL 4 context
948     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
949 }
950 
releaseTexture(QSSGRenderBackendTextureObject to)951 void QSSGRenderBackendGLBase::releaseTexture(QSSGRenderBackendTextureObject to)
952 {
953     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
954     GL_CALL_FUNCTION(glDeleteTextures(1, &texID));
955 }
956 
setTextureData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,qint32 border,QSSGRenderTextureFormat format,QSSGByteView hostData)957 void QSSGRenderBackendGLBase::setTextureData2D(QSSGRenderBackendTextureObject to,
958                                                  QSSGRenderTextureTargetType target,
959                                                  qint32 level,
960                                                  QSSGRenderTextureFormat internalFormat,
961                                                  qint32 width,
962                                                  qint32 height,
963                                                  qint32 border,
964                                                  QSSGRenderTextureFormat format,
965                                                  QSSGByteView hostData)
966 {
967     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
968     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
969     setActiveTexture(GL_TEXTURE0);
970     GL_CALL_FUNCTION(glBindTexture(glTarget, texID));
971     bool conversionRequired = format != internalFormat;
972 
973     QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
974     internalFormat = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), internalFormat, swizzleMode);
975 
976     GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
977 
978     if (internalFormat.isUncompressedTextureFormat())
979         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
980 
981     if (conversionRequired) {
982         GLenum dummy;
983         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, dummy);
984     } else if (internalFormat.isCompressedTextureFormat()) {
985         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
986         glInternalFormat = GLConversion::fromCompressedTextureFormatToGL(internalFormat);
987     } else if (format.isDepthTextureFormat()) {
988         GLConversion::fromDepthTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
989     }
990 
991     GL_CALL_FUNCTION(glTexImage2D(glTarget, level, glInternalFormat, GLsizei(width), GLsizei(height), border, glformat, gltype, hostData));
992 
993     GL_CALL_FUNCTION(glBindTexture(glTarget, 0));
994 }
995 
996 // This will look very SetTextureData2D, but the target for glBindTexture will be different from
997 // the target for
998 // glTexImage2D.
setTextureDataCubeFace(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,qint32 border,QSSGRenderTextureFormat format,QSSGByteView hostData)999 void QSSGRenderBackendGLBase::setTextureDataCubeFace(QSSGRenderBackendTextureObject to,
1000                                                        QSSGRenderTextureTargetType target,
1001                                                        qint32 level,
1002                                                        QSSGRenderTextureFormat internalFormat,
1003                                                        qint32 width,
1004                                                        qint32 height,
1005                                                        qint32 border,
1006                                                        QSSGRenderTextureFormat format,
1007                                                        QSSGByteView hostData)
1008 {
1009     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1010     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1011     GLenum glTexTarget = GLConversion::fromTextureTargetToGL(QSSGRenderTextureTargetType::TextureCube);
1012     setActiveTexture(GL_TEXTURE0);
1013     GL_CALL_FUNCTION(glBindTexture(glTexTarget, texID));
1014     bool conversionRequired = format != internalFormat;
1015 
1016     QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
1017     internalFormat = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), internalFormat, swizzleMode);
1018 
1019     GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
1020 
1021     if (internalFormat.isUncompressedTextureFormat())
1022         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
1023 
1024     if (conversionRequired) {
1025         GLenum dummy;
1026         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, dummy);
1027     } else if (internalFormat.isCompressedTextureFormat()) {
1028         GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
1029         glInternalFormat = GLConversion::fromCompressedTextureFormatToGL(internalFormat);
1030     } else if (format.isDepthTextureFormat()) {
1031         GLConversion::fromDepthTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
1032     }
1033 
1034     // for es2 internal format must be same as format
1035     if (getRenderContextType() == QSSGRenderContextType::GLES2)
1036         glInternalFormat = glformat;
1037 
1038     GL_CALL_FUNCTION(glTexImage2D(glTarget, level, glInternalFormat, GLsizei(width), GLsizei(height), border, glformat, gltype, hostData));
1039 
1040     GL_CALL_FUNCTION(glBindTexture(glTexTarget, 0));
1041 }
1042 
createTextureStorage2D(QSSGRenderBackendTextureObject,QSSGRenderTextureTargetType,qint32,QSSGRenderTextureFormat,qint32,qint32)1043 void QSSGRenderBackendGLBase::createTextureStorage2D(QSSGRenderBackendTextureObject,
1044                                                        QSSGRenderTextureTargetType,
1045                                                        qint32,
1046                                                        QSSGRenderTextureFormat,
1047                                                        qint32,
1048                                                        qint32)
1049 {
1050     // you need GL 4.2 or GLES 3.1
1051     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1052 }
1053 
setTextureSubData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,qint32 xOffset,qint32 yOffset,qint32 width,qint32 height,QSSGRenderTextureFormat format,QSSGByteView hostData)1054 void QSSGRenderBackendGLBase::setTextureSubData2D(QSSGRenderBackendTextureObject to,
1055                                                     QSSGRenderTextureTargetType target,
1056                                                     qint32 level,
1057                                                     qint32 xOffset,
1058                                                     qint32 yOffset,
1059                                                     qint32 width,
1060                                                     qint32 height,
1061                                                     QSSGRenderTextureFormat format,
1062                                                     QSSGByteView hostData)
1063 {
1064     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1065     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1066     setActiveTexture(GL_TEXTURE0);
1067     GL_CALL_FUNCTION(glBindTexture(glTarget, texID));
1068 
1069     QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
1070     format = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), format, swizzleMode);
1071 
1072     GLenum glformat = 0, glInternalFormat = 0, gltype = 0;
1073     GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
1074     GL_CALL_FUNCTION(glTexSubImage2D(glTarget, level, xOffset, yOffset, GLsizei(width), GLsizei(height), glformat, gltype, hostData));
1075 
1076     GL_CALL_FUNCTION(glBindTexture(glTarget, 0));
1077 }
1078 
setCompressedTextureData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,qint32 border,QSSGByteView hostData)1079 void QSSGRenderBackendGLBase::setCompressedTextureData2D(QSSGRenderBackendTextureObject to,
1080                                                            QSSGRenderTextureTargetType target,
1081                                                            qint32 level,
1082                                                            QSSGRenderTextureFormat internalFormat,
1083                                                            qint32 width,
1084                                                            qint32 height,
1085                                                            qint32 border,
1086                                                            QSSGByteView hostData)
1087 {
1088     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1089     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1090     setActiveTexture(GL_TEXTURE0);
1091     GL_CALL_FUNCTION(glBindTexture(glTarget, texID));
1092 
1093     GLenum glformat = GLConversion::fromCompressedTextureFormatToGL(internalFormat);
1094     GL_CALL_FUNCTION(glCompressedTexImage2D(glTarget, level, glformat, GLsizei(width), GLsizei(height), border, GLsizei(hostData.size()), hostData));
1095 
1096     GL_CALL_FUNCTION(glBindTexture(glTarget, 0));
1097 }
1098 
setCompressedTextureDataCubeFace(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,qint32 border,QSSGByteView hostData)1099 void QSSGRenderBackendGLBase::setCompressedTextureDataCubeFace(QSSGRenderBackendTextureObject to,
1100                                                                  QSSGRenderTextureTargetType target,
1101                                                                  qint32 level,
1102                                                                  QSSGRenderTextureFormat internalFormat,
1103                                                                  qint32 width,
1104                                                                  qint32 height,
1105                                                                  qint32 border,
1106                                                                  QSSGByteView hostData)
1107 {
1108     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1109     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1110     GLenum glTexTarget = GLConversion::fromTextureTargetToGL(QSSGRenderTextureTargetType::TextureCube);
1111     setActiveTexture(GL_TEXTURE0);
1112     GL_CALL_FUNCTION(glBindTexture(glTexTarget, texID));
1113 
1114     GLenum glformat = GLConversion::fromCompressedTextureFormatToGL(internalFormat);
1115     GL_CALL_FUNCTION(glCompressedTexImage2D(glTarget, level, glformat, GLsizei(width), GLsizei(height), border, GLsizei(hostData.size()), hostData));
1116 
1117     GL_CALL_FUNCTION(glBindTexture(glTexTarget, 0));
1118 }
1119 
setCompressedTextureSubData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,qint32 xOffset,qint32 yOffset,qint32 width,qint32 height,QSSGRenderTextureFormat format,QSSGByteView hostData)1120 void QSSGRenderBackendGLBase::setCompressedTextureSubData2D(QSSGRenderBackendTextureObject to,
1121                                                               QSSGRenderTextureTargetType target,
1122                                                               qint32 level,
1123                                                               qint32 xOffset,
1124                                                               qint32 yOffset,
1125                                                               qint32 width,
1126                                                               qint32 height,
1127                                                               QSSGRenderTextureFormat format,
1128                                                               QSSGByteView hostData)
1129 {
1130     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1131     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1132     setActiveTexture(GL_TEXTURE0);
1133     GL_CALL_FUNCTION(glBindTexture(glTarget, texID));
1134 
1135     GLenum glformat = GLConversion::fromCompressedTextureFormatToGL(format);
1136     GL_CALL_FUNCTION(
1137             glCompressedTexSubImage2D(glTarget, level, xOffset, yOffset, GLsizei(width), GLsizei(height), glformat, GLsizei(hostData.size()), hostData));
1138 
1139     GL_CALL_FUNCTION(glBindTexture(glTarget, 0));
1140 }
1141 
setTextureData3D(QSSGRenderBackendTextureObject,QSSGRenderTextureTargetType,qint32,QSSGRenderTextureFormat,qint32,qint32,qint32,qint32,QSSGRenderTextureFormat,QSSGByteView)1142 void QSSGRenderBackendGLBase::setTextureData3D(QSSGRenderBackendTextureObject,
1143                                                  QSSGRenderTextureTargetType,
1144                                                  qint32,
1145                                                  QSSGRenderTextureFormat,
1146                                                  qint32,
1147                                                  qint32,
1148                                                  qint32,
1149                                                  qint32,
1150                                                  QSSGRenderTextureFormat,
1151                                                  QSSGByteView)
1152 {
1153     // needs GL3 or GLES3
1154     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1155 }
1156 
generateMipMaps(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,QSSGRenderHint genType)1157 void QSSGRenderBackendGLBase::generateMipMaps(QSSGRenderBackendTextureObject to,
1158                                                 QSSGRenderTextureTargetType target,
1159                                                 QSSGRenderHint genType)
1160 {
1161     GLuint texID = HandleToID_cast(GLuint, quintptr, to);
1162     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1163     setActiveTexture(GL_TEXTURE0);
1164     GL_CALL_FUNCTION(glBindTexture(glTarget, texID));
1165 
1166     GLenum glValue = GLConversion::fromHintToGL(genType);
1167     GL_CALL_FUNCTION(glHint(GL_GENERATE_MIPMAP_HINT, glValue));
1168     GL_CALL_FUNCTION(glGenerateMipmap(glTarget));
1169 
1170     GL_CALL_FUNCTION(glBindTexture(glTarget, 0));
1171 }
1172 
getTextureSwizzleMode(const QSSGRenderTextureFormat inFormat) const1173 QSSGRenderTextureSwizzleMode QSSGRenderBackendGLBase::getTextureSwizzleMode(const QSSGRenderTextureFormat inFormat) const
1174 {
1175     QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
1176     GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), inFormat, swizzleMode);
1177 
1178     return swizzleMode;
1179 }
1180 
createSampler(QSSGRenderTextureMinifyingOp minFilter,QSSGRenderTextureMagnifyingOp magFilter,QSSGRenderTextureCoordOp wrapS,QSSGRenderTextureCoordOp wrapT,QSSGRenderTextureCoordOp wrapR,qint32 minLod,qint32 maxLod,float lodBias,QSSGRenderTextureCompareMode compareMode,QSSGRenderTextureCompareOp compareFunc,float anisotropy,float * borderColor)1181 QSSGRenderBackend::QSSGRenderBackendSamplerObject QSSGRenderBackendGLBase::createSampler(
1182         QSSGRenderTextureMinifyingOp minFilter,
1183         QSSGRenderTextureMagnifyingOp magFilter,
1184         QSSGRenderTextureCoordOp wrapS,
1185         QSSGRenderTextureCoordOp wrapT,
1186         QSSGRenderTextureCoordOp wrapR,
1187         qint32 minLod,
1188         qint32 maxLod,
1189         float lodBias,
1190         QSSGRenderTextureCompareMode compareMode,
1191         QSSGRenderTextureCompareOp compareFunc,
1192         float anisotropy,
1193         float *borderColor)
1194 {
1195     // Satisfy the compiler
1196     // We don"t setup the state here for GL
1197     // but we need to pass on the variables here
1198     // to satisfy the interface
1199     Q_UNUSED(minFilter)
1200     Q_UNUSED(magFilter)
1201     Q_UNUSED(wrapS)
1202     Q_UNUSED(wrapT)
1203     Q_UNUSED(wrapR)
1204     Q_UNUSED(minLod)
1205     Q_UNUSED(maxLod)
1206     Q_UNUSED(lodBias)
1207     Q_UNUSED(compareMode)
1208     Q_UNUSED(compareFunc)
1209     Q_UNUSED(anisotropy)
1210     Q_UNUSED(borderColor)
1211 
1212     // return a dummy handle
1213     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendSamplerObject>(0x0001);
1214 }
1215 
updateSampler(QSSGRenderBackendSamplerObject,QSSGRenderTextureTargetType target,QSSGRenderTextureMinifyingOp minFilter,QSSGRenderTextureMagnifyingOp magFilter,QSSGRenderTextureCoordOp wrapS,QSSGRenderTextureCoordOp wrapT,QSSGRenderTextureCoordOp wrapR,float minLod,float maxLod,float lodBias,QSSGRenderTextureCompareMode compareMode,QSSGRenderTextureCompareOp compareFunc,float anisotropy,float * borderColor)1216 void QSSGRenderBackendGLBase::updateSampler(QSSGRenderBackendSamplerObject /* so */,
1217                                               QSSGRenderTextureTargetType target,
1218                                               QSSGRenderTextureMinifyingOp minFilter,
1219                                               QSSGRenderTextureMagnifyingOp magFilter,
1220                                               QSSGRenderTextureCoordOp wrapS,
1221                                               QSSGRenderTextureCoordOp wrapT,
1222                                               QSSGRenderTextureCoordOp wrapR,
1223                                               float minLod,
1224                                               float maxLod,
1225                                               float lodBias,
1226                                               QSSGRenderTextureCompareMode compareMode,
1227                                               QSSGRenderTextureCompareOp compareFunc,
1228                                               float anisotropy,
1229                                               float *borderColor)
1230 {
1231     // Satisfy the compiler
1232     // These are not available in GLES 2 and we don't use them right now
1233     Q_UNUSED(wrapR)
1234     Q_UNUSED(lodBias)
1235     Q_UNUSED(minLod)
1236     Q_UNUSED(maxLod)
1237     Q_UNUSED(compareMode)
1238     Q_UNUSED(compareFunc)
1239     Q_UNUSED(borderColor)
1240 
1241     GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
1242 
1243     GL_CALL_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MIN_FILTER, m_conversion.fromTextureMinifyingOpToGL(minFilter)));
1244     GL_CALL_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MAG_FILTER, m_conversion.fromTextureMagnifyingOpToGL(magFilter)));
1245     GL_CALL_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_S, m_conversion.fromTextureCoordOpToGL(wrapS)));
1246     GL_CALL_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_T, m_conversion.fromTextureCoordOpToGL(wrapT)));
1247     if (m_backendSupport.caps.bits.bAnistropySupported) {
1248         GL_CALL_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy));
1249     }
1250 }
1251 
updateTextureObject(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 baseLevel,qint32 maxLevel)1252 void QSSGRenderBackendGLBase::updateTextureObject(QSSGRenderBackendTextureObject to,
1253                                                     QSSGRenderTextureTargetType target,
1254                                                     qint32 baseLevel,
1255                                                     qint32 maxLevel)
1256 {
1257     Q_UNUSED(to)
1258     Q_UNUSED(target)
1259     Q_UNUSED(baseLevel)
1260     Q_UNUSED(maxLevel)
1261 }
1262 
updateTextureSwizzle(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,QSSGRenderTextureSwizzleMode swizzleMode)1263 void QSSGRenderBackendGLBase::updateTextureSwizzle(QSSGRenderBackendTextureObject to,
1264                                                      QSSGRenderTextureTargetType target,
1265                                                      QSSGRenderTextureSwizzleMode swizzleMode)
1266 {
1267     Q_UNUSED(to)
1268     Q_UNUSED(target)
1269 
1270     // Nothing to do here still might be called
1271     Q_ASSERT(swizzleMode == QSSGRenderTextureSwizzleMode::NoSwizzle);
1272 
1273     Q_UNUSED(swizzleMode)
1274 }
1275 
releaseSampler(QSSGRenderBackendSamplerObject so)1276 void QSSGRenderBackendGLBase::releaseSampler(QSSGRenderBackendSamplerObject so)
1277 {
1278     GLuint samplerID = HandleToID_cast(GLuint, quintptr, so);
1279     if (!samplerID)
1280         return;
1281     // otherwise nothing to do
1282 }
1283 
createAttribLayout(QSSGDataView<QSSGRenderVertexBufferEntry> attribs)1284 QSSGRenderBackend::QSSGRenderBackendAttribLayoutObject QSSGRenderBackendGLBase::createAttribLayout(
1285         QSSGDataView<QSSGRenderVertexBufferEntry> attribs)
1286 {
1287     quint32 attribLayoutSize = sizeof(QSSGRenderBackendAttributeLayoutGL);
1288     quint32 entrySize = sizeof(QSSGRenderBackendLayoutEntryGL) * attribs.size();
1289     quint8 *newMem = static_cast<quint8 *>(::malloc(attribLayoutSize + entrySize));
1290     QSSGDataRef<QSSGRenderBackendLayoutEntryGL> entryRef = PtrAtOffset<QSSGRenderBackendLayoutEntryGL>(newMem, attribLayoutSize, entrySize);
1291     quint32 maxInputSlot = 0;
1292 
1293     // copy data
1294     for (int idx = 0; idx != attribs.size(); ++idx) {
1295         new (&entryRef[idx]) QSSGRenderBackendLayoutEntryGL();
1296         entryRef[idx].m_attribName = attribs.mData[idx].m_name;
1297         entryRef[idx].m_normalize = 0;
1298         entryRef[idx].m_attribIndex = 0; // will be set later
1299         entryRef[idx].m_type = GLConversion::fromComponentTypeAndNumCompsToAttribGL(attribs.mData[idx].m_componentType,
1300                                                                                     attribs.mData[idx].m_numComponents);
1301         entryRef[idx].m_numComponents = attribs.mData[idx].m_numComponents;
1302         entryRef[idx].m_inputSlot = attribs.mData[idx].m_inputSlot;
1303         entryRef[idx].m_offset = attribs.mData[idx].m_firstItemOffset;
1304 
1305         if (maxInputSlot < entryRef[idx].m_inputSlot)
1306             maxInputSlot = entryRef[idx].m_inputSlot;
1307     }
1308 
1309     QSSGRenderBackendAttributeLayoutGL *retval = new (newMem) QSSGRenderBackendAttributeLayoutGL(entryRef, maxInputSlot);
1310 
1311     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendAttribLayoutObject>(retval);
1312 }
1313 
releaseAttribLayout(QSSGRenderBackendAttribLayoutObject ao)1314 void QSSGRenderBackendGLBase::releaseAttribLayout(QSSGRenderBackendAttribLayoutObject ao)
1315 {
1316     QSSGRenderBackendAttributeLayoutGL *attribLayout = reinterpret_cast<QSSGRenderBackendAttributeLayoutGL *>(ao);
1317     if (attribLayout) { // Created with malloc, so release with free!
1318         attribLayout->~QSSGRenderBackendAttributeLayoutGL();
1319         ::free(attribLayout);
1320         attribLayout = nullptr;
1321     }
1322 };
1323 
createInputAssembler(QSSGRenderBackendAttribLayoutObject attribLayout,QSSGDataView<QSSGRenderBackendBufferObject> buffers,const QSSGRenderBackendBufferObject indexBuffer,QSSGDataView<quint32> strides,QSSGDataView<quint32> offsets,quint32 patchVertexCount)1324 QSSGRenderBackend::QSSGRenderBackendInputAssemblerObject QSSGRenderBackendGLBase::createInputAssembler(
1325         QSSGRenderBackendAttribLayoutObject attribLayout,
1326         QSSGDataView<QSSGRenderBackendBufferObject> buffers,
1327         const QSSGRenderBackendBufferObject indexBuffer,
1328         QSSGDataView<quint32> strides,
1329         QSSGDataView<quint32> offsets,
1330         quint32 patchVertexCount)
1331 {
1332     QSSGRenderBackendAttributeLayoutGL *attribLayoutGL = reinterpret_cast<QSSGRenderBackendAttributeLayoutGL *>(attribLayout);
1333 
1334     QSSGRenderBackendInputAssemblerGL *retval = new QSSGRenderBackendInputAssemblerGL(attribLayoutGL,
1335                                                                                           buffers,
1336                                                                                           indexBuffer,
1337                                                                                           strides,
1338                                                                                           offsets,
1339                                                                                           patchVertexCount);
1340 
1341     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendInputAssemblerObject>(retval);
1342 }
1343 
releaseInputAssembler(QSSGRenderBackendInputAssemblerObject iao)1344 void QSSGRenderBackendGLBase::releaseInputAssembler(QSSGRenderBackendInputAssemblerObject iao)
1345 {
1346     QSSGRenderBackendInputAssemblerGL *inputAssembler = reinterpret_cast<QSSGRenderBackendInputAssemblerGL *>(iao);
1347     delete inputAssembler;
1348 }
1349 
resetStates()1350 void QSSGRenderBackendGLBase::resetStates()
1351 {
1352     m_usedAttribCount = m_maxAttribCount;
1353     m_activatedTextureUnit = ACTIVATED_TEXTURE_UNIT_UNKNOWN;
1354 }
1355 
compileSource(GLuint shaderID,QSSGByteView source,QByteArray & errorMessage,bool binary)1356 bool QSSGRenderBackendGLBase::compileSource(GLuint shaderID, QSSGByteView source, QByteArray &errorMessage, bool binary)
1357 {
1358     GLint shaderSourceSize = static_cast<GLint>(source.size());
1359     const char *shaderSourceData = reinterpret_cast<const char *>(source.begin());
1360     GLint shaderStatus = GL_TRUE;
1361 
1362     if (!binary) {
1363 
1364         GL_CALL_FUNCTION(glShaderSource(shaderID, 1, &shaderSourceData, &shaderSourceSize));
1365         GL_CALL_FUNCTION(glCompileShader(shaderID));
1366 
1367         GLint logLen;
1368         GL_CALL_FUNCTION(glGetShaderiv(shaderID, GL_COMPILE_STATUS, &shaderStatus));
1369         GL_CALL_FUNCTION(glGetShaderiv(shaderID, GL_INFO_LOG_LENGTH, &logLen));
1370 
1371         // Check if some log exists. We also write warnings here
1372         // Should at least contain more than the null termination
1373         if (logLen > 2) {
1374             errorMessage.resize(logLen + 1);
1375 
1376             GLint lenWithoutNull;
1377             GL_CALL_FUNCTION(glGetShaderInfoLog(shaderID, logLen, &lenWithoutNull, errorMessage.data()));
1378         }
1379     } else {
1380         GL_CALL_FUNCTION(glShaderBinary(1, &shaderID, GL_NVIDIA_PLATFORM_BINARY_NV, shaderSourceData, shaderSourceSize));
1381         GLenum binaryError = m_glFunctions->glGetError();
1382         if (binaryError != GL_NO_ERROR) {
1383             errorMessage = QByteArrayLiteral("Binary shader compilation failed");
1384             shaderStatus = GL_FALSE;
1385             qCCritical(RENDER_GL_ERROR, "%s", GLConversion::processGLError(binaryError));
1386         }
1387     }
1388 
1389     return (shaderStatus == GL_TRUE);
1390 }
1391 
createVertexShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1392 QSSGRenderBackend::QSSGRenderBackendVertexShaderObject QSSGRenderBackendGLBase::createVertexShader(QSSGByteView source,
1393                                                                                                          QByteArray &errorMessage,
1394                                                                                                          bool binary)
1395 {
1396     GLuint shaderID = GL_CALL_FUNCTION(glCreateShader(GL_VERTEX_SHADER));
1397 
1398     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
1399         GL_CALL_FUNCTION(glDeleteShader(shaderID));
1400         shaderID = 0;
1401     }
1402 
1403     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendVertexShaderObject>(quintptr(shaderID));
1404 }
1405 
createFragmentShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1406 QSSGRenderBackend::QSSGRenderBackendFragmentShaderObject QSSGRenderBackendGLBase::createFragmentShader(QSSGByteView source,
1407                                                                                                              QByteArray &errorMessage,
1408                                                                                                              bool binary)
1409 {
1410     GLuint shaderID = GL_CALL_FUNCTION(glCreateShader(GL_FRAGMENT_SHADER));
1411 
1412     if (shaderID && !compileSource(shaderID, source, errorMessage, binary)) {
1413         GL_CALL_FUNCTION(glDeleteShader(shaderID));
1414         shaderID = 0;
1415     }
1416 
1417     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendFragmentShaderObject>(quintptr(shaderID));
1418 }
1419 
createTessControlShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1420 QSSGRenderBackend::QSSGRenderBackendTessControlShaderObject QSSGRenderBackendGLBase::createTessControlShader(
1421         QSSGByteView source,
1422         QByteArray &errorMessage,
1423         bool binary)
1424 {
1425     // needs GL 4 or GLES EXT_tessellation_shader support
1426     Q_UNUSED(source)
1427     Q_UNUSED(errorMessage)
1428     Q_UNUSED(binary)
1429 
1430     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1431 
1432     return nullptr;
1433 }
1434 
createTessEvaluationShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1435 QSSGRenderBackend::QSSGRenderBackendTessEvaluationShaderObject QSSGRenderBackendGLBase::createTessEvaluationShader(
1436         QSSGByteView source,
1437         QByteArray &errorMessage,
1438         bool binary)
1439 {
1440     // needs GL 4 or GLES EXT_tessellation_shader support
1441     Q_UNUSED(source)
1442     Q_UNUSED(errorMessage)
1443     Q_UNUSED(binary)
1444 
1445     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1446 
1447     return nullptr;
1448 }
1449 
createGeometryShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1450 QSSGRenderBackend::QSSGRenderBackendGeometryShaderObject QSSGRenderBackendGLBase::createGeometryShader(QSSGByteView source,
1451                                                                                                              QByteArray &errorMessage,
1452                                                                                                              bool binary)
1453 {
1454     // needs GL 4 or GLES EXT_geometry_shader support
1455     Q_UNUSED(source)
1456     Q_UNUSED(errorMessage)
1457     Q_UNUSED(binary)
1458 
1459     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1460 
1461     return nullptr;
1462 }
1463 
createComputeShader(QSSGByteView source,QByteArray & errorMessage,bool binary)1464 QSSGRenderBackend::QSSGRenderBackendComputeShaderObject QSSGRenderBackendGLBase::createComputeShader(QSSGByteView source,
1465                                                                                                            QByteArray &errorMessage,
1466                                                                                                            bool binary)
1467 {
1468     // needs GL 4.3 or GLES3.1 support
1469     Q_UNUSED(source)
1470     Q_UNUSED(errorMessage)
1471     Q_UNUSED(binary)
1472 
1473     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1474 
1475     return nullptr;
1476 }
1477 
releaseVertexShader(QSSGRenderBackendVertexShaderObject vso)1478 void QSSGRenderBackendGLBase::releaseVertexShader(QSSGRenderBackendVertexShaderObject vso)
1479 {
1480     GLuint shaderID = HandleToID_cast(GLuint, quintptr, vso);
1481 
1482     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1483 }
1484 
releaseFragmentShader(QSSGRenderBackendFragmentShaderObject fso)1485 void QSSGRenderBackendGLBase::releaseFragmentShader(QSSGRenderBackendFragmentShaderObject fso)
1486 {
1487     GLuint shaderID = HandleToID_cast(GLuint, quintptr, fso);
1488 
1489     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1490 }
1491 
releaseTessControlShader(QSSGRenderBackendTessControlShaderObject tcso)1492 void QSSGRenderBackendGLBase::releaseTessControlShader(QSSGRenderBackendTessControlShaderObject tcso)
1493 {
1494     GLuint shaderID = HandleToID_cast(GLuint, quintptr, tcso);
1495 
1496     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1497 }
1498 
releaseTessEvaluationShader(QSSGRenderBackendTessEvaluationShaderObject teso)1499 void QSSGRenderBackendGLBase::releaseTessEvaluationShader(QSSGRenderBackendTessEvaluationShaderObject teso)
1500 {
1501     GLuint shaderID = HandleToID_cast(GLuint, quintptr, teso);
1502 
1503     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1504 }
1505 
releaseGeometryShader(QSSGRenderBackendGeometryShaderObject gso)1506 void QSSGRenderBackendGLBase::releaseGeometryShader(QSSGRenderBackendGeometryShaderObject gso)
1507 {
1508     GLuint shaderID = HandleToID_cast(GLuint, quintptr, gso);
1509 
1510     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1511 }
1512 
releaseComputeShader(QSSGRenderBackendComputeShaderObject cso)1513 void QSSGRenderBackendGLBase::releaseComputeShader(QSSGRenderBackendComputeShaderObject cso)
1514 {
1515     GLuint shaderID = HandleToID_cast(GLuint, quintptr, cso);
1516 
1517     GL_CALL_FUNCTION(glDeleteShader(shaderID));
1518 }
1519 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendVertexShaderObject vso)1520 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendVertexShaderObject vso)
1521 {
1522     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1523     GLuint shaderID = HandleToID_cast(GLuint, quintptr, vso);
1524 
1525     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1526 }
1527 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendFragmentShaderObject fso)1528 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendFragmentShaderObject fso)
1529 {
1530     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1531     GLuint shaderID = HandleToID_cast(GLuint, quintptr, fso);
1532 
1533     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1534 }
1535 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendTessControlShaderObject tcso)1536 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendTessControlShaderObject tcso)
1537 {
1538     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1539     GLuint shaderID = HandleToID_cast(GLuint, quintptr, tcso);
1540 
1541     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1542 }
1543 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendTessEvaluationShaderObject teso)1544 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendTessEvaluationShaderObject teso)
1545 {
1546     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1547     GLuint shaderID = HandleToID_cast(GLuint, quintptr, teso);
1548 
1549     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1550 }
1551 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendGeometryShaderObject gso)1552 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendGeometryShaderObject gso)
1553 {
1554     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1555     GLuint shaderID = HandleToID_cast(GLuint, quintptr, gso);
1556 
1557     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1558 }
1559 
attachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendComputeShaderObject cso)1560 void QSSGRenderBackendGLBase::attachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendComputeShaderObject cso)
1561 {
1562     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1563     GLuint shaderID = HandleToID_cast(GLuint, quintptr, cso);
1564 
1565     GL_CALL_FUNCTION(glAttachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1566 }
1567 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendVertexShaderObject vso)1568 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendVertexShaderObject vso)
1569 {
1570     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1571     GLuint shaderID = HandleToID_cast(GLuint, quintptr, vso);
1572 
1573     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1574 }
1575 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendFragmentShaderObject fso)1576 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendFragmentShaderObject fso)
1577 {
1578     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1579     GLuint shaderID = HandleToID_cast(GLuint, quintptr, fso);
1580 
1581     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1582 }
1583 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendTessControlShaderObject tcso)1584 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendTessControlShaderObject tcso)
1585 {
1586     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1587     GLuint shaderID = HandleToID_cast(GLuint, quintptr, tcso);
1588 
1589     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1590 }
1591 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendTessEvaluationShaderObject teso)1592 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendTessEvaluationShaderObject teso)
1593 {
1594     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1595     GLuint shaderID = HandleToID_cast(GLuint, quintptr, teso);
1596 
1597     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1598 }
1599 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendGeometryShaderObject gso)1600 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendGeometryShaderObject gso)
1601 {
1602     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1603     GLuint shaderID = HandleToID_cast(GLuint, quintptr, gso);
1604 
1605     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1606 }
1607 
detachShader(QSSGRenderBackendShaderProgramObject po,QSSGRenderBackendComputeShaderObject cso)1608 void QSSGRenderBackendGLBase::detachShader(QSSGRenderBackendShaderProgramObject po, QSSGRenderBackendComputeShaderObject cso)
1609 {
1610     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1611     GLuint shaderID = HandleToID_cast(GLuint, quintptr, cso);
1612 
1613     GL_CALL_FUNCTION(glDetachShader(static_cast<GLuint>(pProgram->m_programID), shaderID));
1614 }
1615 
createShaderProgram(bool isSeparable)1616 QSSGRenderBackend::QSSGRenderBackendShaderProgramObject QSSGRenderBackendGLBase::createShaderProgram(bool isSeparable)
1617 {
1618     QSSGRenderBackendShaderProgramGL *theProgram = nullptr;
1619     GLuint programID = GL_CALL_FUNCTION(glCreateProgram());
1620 
1621     if (programID) {
1622         theProgram = new QSSGRenderBackendShaderProgramGL(programID);
1623 
1624         if (!theProgram) {
1625             GL_CALL_FUNCTION(glDeleteProgram(programID));
1626         } else if (isSeparable && m_backendSupport.caps.bits.bProgramPipelineSupported) {
1627             GL_CALL_EXTRA_FUNCTION(glProgramParameteri(programID, GL_PROGRAM_SEPARABLE, GL_TRUE));
1628         }
1629     }
1630 
1631     return reinterpret_cast<QSSGRenderBackend::QSSGRenderBackendShaderProgramObject>(theProgram);
1632 }
1633 
releaseShaderProgram(QSSGRenderBackendShaderProgramObject po)1634 void QSSGRenderBackendGLBase::releaseShaderProgram(QSSGRenderBackendShaderProgramObject po)
1635 {
1636     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1637     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1638 
1639     GL_CALL_FUNCTION(glDeleteProgram(programID));
1640 
1641     delete pProgram;
1642 }
1643 
getAttributes(QSSGRenderBackendShaderProgramGL * pProgram)1644 void QSSGRenderBackendGLBase::getAttributes(QSSGRenderBackendShaderProgramGL *pProgram)
1645 {
1646     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1647     // release old stuff
1648     if (pProgram->m_shaderInput) {
1649         delete pProgram->m_shaderInput;
1650         pProgram->m_shaderInput = nullptr;
1651     }
1652 
1653     GLint numAttribs;
1654     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTES, &numAttribs));
1655 
1656     if (numAttribs) {
1657         QSSGRenderBackendShaderInputEntryGL *tempShaderInputEntry = static_cast<QSSGRenderBackendShaderInputEntryGL *>(
1658                 ::malloc(sizeof(QSSGRenderBackendShaderInputEntryGL) * size_t(m_maxAttribCount)));
1659 
1660         GLint maxLength;
1661         GL_CALL_FUNCTION(glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &maxLength));
1662         qint8 *nameBuf = static_cast<qint8 *>(::malloc(size_t(maxLength)));
1663 
1664         // fill in data
1665         qint32 count = 0;
1666         for (int idx = 0; idx != numAttribs; ++idx) {
1667             GLint size = 0;
1668             GLenum glType;
1669             QSSGRenderComponentType compType = QSSGRenderComponentType::Unknown;
1670             quint32 numComps = 0;
1671 
1672             GL_CALL_FUNCTION(glGetActiveAttrib(programID, idx, maxLength, nullptr, &size, &glType, (char *)nameBuf));
1673             // Skip anything named with gl_
1674             if (memcmp(nameBuf, "gl_", 3) == 0)
1675                 continue;
1676 
1677             GLConversion::fromAttribGLToComponentTypeAndNumComps(glType, compType, numComps);
1678 
1679             new (&tempShaderInputEntry[count]) QSSGRenderBackendShaderInputEntryGL();
1680             tempShaderInputEntry[count].m_attribName = QByteArray(reinterpret_cast<const char *>(nameBuf));
1681             tempShaderInputEntry[count].m_attribLocation = GL_CALL_FUNCTION(glGetAttribLocation(programID, (char *)nameBuf));
1682             tempShaderInputEntry[count].m_type = glType;
1683             tempShaderInputEntry[count].m_numComponents = numComps;
1684 
1685             ++count;
1686         }
1687 
1688         // Now allocate space for the actuall entries
1689         quint32 shaderInputSize = sizeof(QSSGRenderBackendShaderInputGL);
1690         quint32 entrySize = sizeof(QSSGRenderBackendShaderInputEntryGL) * count;
1691         quint8 *newMem = static_cast<quint8 *>(::malloc(shaderInputSize + entrySize));
1692         QSSGDataRef<QSSGRenderBackendShaderInputEntryGL> entryRef = PtrAtOffset<QSSGRenderBackendShaderInputEntryGL>(newMem, shaderInputSize, entrySize);
1693         // fill data
1694         for (int idx = 0; idx != count; ++idx) {
1695             new (&entryRef[idx]) QSSGRenderBackendShaderInputEntryGL();
1696             entryRef[idx].m_attribName = tempShaderInputEntry[idx].m_attribName;
1697             entryRef[idx].m_attribLocation = tempShaderInputEntry[idx].m_attribLocation;
1698             entryRef[idx].m_type = tempShaderInputEntry[idx].m_type;
1699             entryRef[idx].m_numComponents = tempShaderInputEntry[idx].m_numComponents;
1700             // Re-set the entry to release the QByteArray, we can do the plane free later
1701             tempShaderInputEntry[idx] = QSSGRenderBackendShaderInputEntryGL();
1702         }
1703 
1704         // placement new
1705         QSSGRenderBackendShaderInputGL *shaderInput = new (newMem) QSSGRenderBackendShaderInputGL(entryRef);
1706         // set the pointer
1707         pProgram->m_shaderInput = shaderInput;
1708 
1709         ::free(nameBuf);
1710         ::free(tempShaderInputEntry);
1711     }
1712 }
1713 
linkProgram(QSSGRenderBackendShaderProgramObject po,QByteArray & errorMessage)1714 bool QSSGRenderBackendGLBase::linkProgram(QSSGRenderBackendShaderProgramObject po, QByteArray &errorMessage)
1715 {
1716     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1717     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1718 
1719     GL_CALL_FUNCTION(glLinkProgram(programID));
1720 
1721     GLint linkStatus, logLen;
1722     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus));
1723     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &logLen));
1724 
1725     // if successfully linked get the attribute information
1726     if (linkStatus)
1727         getAttributes(pProgram);
1728 
1729     // Check if some log exists. We also write warnings here
1730     // Should at least contain more than the null termination
1731     if (logLen > 2) {
1732         errorMessage.resize(logLen + 1);
1733 
1734         GLint lenWithoutNull;
1735         GL_CALL_FUNCTION(glGetProgramInfoLog(programID, logLen, &lenWithoutNull, errorMessage.data()));
1736     }
1737 
1738     return (linkStatus == GL_TRUE);
1739 }
1740 
linkProgram(QSSGRenderBackendShaderProgramObject po,QByteArray & errorMessage,quint32 format,const QByteArray & binary)1741 bool QSSGRenderBackendGLBase::linkProgram(QSSGRenderBackendShaderProgramObject po,
1742                                           QByteArray &errorMessage,
1743                                           quint32 format, const QByteArray &binary)
1744 {
1745     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1746     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1747 
1748     GL_CALL_EXTRA_FUNCTION(glProgramBinary(programID, GLenum(format), binary.constData(), binary.size()));
1749 
1750     GLint linkStatus, logLen;
1751     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus));
1752     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_INFO_LOG_LENGTH, &logLen));
1753 
1754     // if successfully linked get the attribute information
1755     if (linkStatus)
1756         getAttributes(pProgram);
1757 
1758     // Check if some log exists. We also write warnings here
1759     // Should at least contain more than the null termination
1760     if (logLen > 2) {
1761         errorMessage.resize(logLen + 1);
1762 
1763         GLint lenWithoutNull;
1764         GL_CALL_FUNCTION(glGetProgramInfoLog(programID, logLen, &lenWithoutNull, errorMessage.data()));
1765     }
1766 
1767     return (linkStatus == GL_TRUE);
1768 }
1769 
getProgramBinary(QSSGRenderBackendShaderProgramObject po,quint32 & format,QByteArray & binary)1770 void QSSGRenderBackendGLBase::getProgramBinary(QSSGRenderBackendShaderProgramObject po, quint32 &format, QByteArray &binary)
1771 {
1772     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1773     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1774     GLint binLen, linkStatus;
1775 
1776     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus));
1777     Q_ASSERT(linkStatus == GL_TRUE);
1778 
1779     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_PROGRAM_BINARY_LENGTH, &binLen));
1780 
1781     binary.resize(binLen);
1782     GLenum fmt;
1783     GL_CALL_EXTRA_FUNCTION(glGetProgramBinary(programID, binLen, nullptr, &fmt,
1784                                               binary.data()));
1785     format = fmt;
1786 }
1787 
setActiveProgram(QSSGRenderBackendShaderProgramObject po)1788 void QSSGRenderBackendGLBase::setActiveProgram(QSSGRenderBackendShaderProgramObject po)
1789 {
1790     GLuint programID = 0;
1791 
1792     if (po) {
1793         QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1794         programID = static_cast<GLuint>(pProgram->m_programID);
1795     }
1796 
1797     GL_CALL_FUNCTION(glUseProgram(programID));
1798 }
1799 
createProgramPipeline()1800 QSSGRenderBackend::QSSGRenderBackendProgramPipeline QSSGRenderBackendGLBase::createProgramPipeline()
1801 {
1802     // needs GL 4 context
1803     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1804     return QSSGRenderBackend::QSSGRenderBackendProgramPipeline(nullptr);
1805 }
1806 
releaseProgramPipeline(QSSGRenderBackendProgramPipeline)1807 void QSSGRenderBackendGLBase::releaseProgramPipeline(QSSGRenderBackendProgramPipeline)
1808 {
1809     // needs GL 4 context
1810     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1811 }
1812 
setActiveProgramPipeline(QSSGRenderBackendProgramPipeline)1813 void QSSGRenderBackendGLBase::setActiveProgramPipeline(QSSGRenderBackendProgramPipeline)
1814 {
1815     // needs GL 4 context
1816     // TODO: should be fixed?
1817     //        Q_ASSERT(false);
1818 }
1819 
setProgramStages(QSSGRenderBackendProgramPipeline,QSSGRenderShaderTypeFlags,QSSGRenderBackendShaderProgramObject)1820 void QSSGRenderBackendGLBase::setProgramStages(QSSGRenderBackendProgramPipeline, QSSGRenderShaderTypeFlags, QSSGRenderBackendShaderProgramObject)
1821 {
1822     // needs GL 4 context
1823     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1824 }
1825 
dispatchCompute(QSSGRenderBackendShaderProgramObject,quint32,quint32,quint32)1826 void QSSGRenderBackendGLBase::dispatchCompute(QSSGRenderBackendShaderProgramObject, quint32, quint32, quint32)
1827 {
1828     // needs GL 4 context
1829     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1830 }
1831 
getConstantCount(QSSGRenderBackendShaderProgramObject po)1832 qint32 QSSGRenderBackendGLBase::getConstantCount(QSSGRenderBackendShaderProgramObject po)
1833 {
1834     Q_ASSERT(po);
1835     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1836     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1837 
1838     GLint numUniforms;
1839     GL_CALL_FUNCTION(glGetProgramiv(programID, GL_ACTIVE_UNIFORMS, &numUniforms));
1840 
1841     return numUniforms;
1842 }
1843 
getConstantBufferCount(QSSGRenderBackendShaderProgramObject po)1844 qint32 QSSGRenderBackendGLBase::getConstantBufferCount(QSSGRenderBackendShaderProgramObject po)
1845 {
1846     // needs GL3 and above
1847     Q_UNUSED(po)
1848 
1849     return 0;
1850 }
1851 
getConstantInfoByID(QSSGRenderBackendShaderProgramObject po,quint32 id,quint32 bufSize,qint32 * numElem,QSSGRenderShaderDataType * type,qint32 * binding,char * nameBuf)1852 qint32 QSSGRenderBackendGLBase::getConstantInfoByID(QSSGRenderBackendShaderProgramObject po,
1853                                                       quint32 id,
1854                                                       quint32 bufSize,
1855                                                       qint32 *numElem,
1856                                                       QSSGRenderShaderDataType *type,
1857                                                       qint32 *binding,
1858                                                       char *nameBuf)
1859 {
1860     Q_ASSERT(po);
1861     QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
1862     GLuint programID = static_cast<GLuint>(pProgram->m_programID);
1863 
1864     GLenum glType;
1865     GL_CALL_FUNCTION(glGetActiveUniform(programID, id, GLsizei(bufSize), nullptr, numElem, &glType, nameBuf));
1866     *type = GLConversion::fromShaderGLToPropertyDataTypes(glType);
1867 
1868     qint32 uniformLoc = GL_CALL_FUNCTION(glGetUniformLocation(programID, nameBuf));
1869 
1870     // get unit binding point
1871     *binding = -1;
1872     if (uniformLoc != -1 && (glType == GL_IMAGE_2D || glType == GL_UNSIGNED_INT_IMAGE_2D || glType == GL_UNSIGNED_INT_ATOMIC_COUNTER)) {
1873         GL_CALL_FUNCTION(glGetUniformiv(programID, uniformLoc, binding));
1874     }
1875 
1876     return uniformLoc;
1877 }
1878 
getConstantBufferInfoByID(QSSGRenderBackendShaderProgramObject po,quint32 id,quint32 nameBufSize,qint32 * paramCount,qint32 * bufferSize,qint32 * length,char * nameBuf)1879 qint32 QSSGRenderBackendGLBase::getConstantBufferInfoByID(QSSGRenderBackendShaderProgramObject po,
1880                                                             quint32 id,
1881                                                             quint32 nameBufSize,
1882                                                             qint32 *paramCount,
1883                                                             qint32 *bufferSize,
1884                                                             qint32 *length,
1885                                                             char *nameBuf)
1886 {
1887     // needs GL3 and above
1888     Q_UNUSED(po)
1889     Q_UNUSED(id)
1890     Q_UNUSED(nameBufSize)
1891     Q_UNUSED(paramCount)
1892     Q_UNUSED(bufferSize)
1893     Q_UNUSED(length)
1894     Q_UNUSED(nameBuf)
1895 
1896     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1897 
1898     return -1;
1899 }
1900 
getConstantBufferParamIndices(QSSGRenderBackendShaderProgramObject po,quint32 id,qint32 * indices)1901 void QSSGRenderBackendGLBase::getConstantBufferParamIndices(QSSGRenderBackendShaderProgramObject po, quint32 id, qint32 *indices)
1902 {
1903     // needs GL3 and above
1904     Q_UNUSED(po)
1905     Q_UNUSED(id)
1906     Q_UNUSED(indices)
1907 
1908     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1909 }
1910 
getConstantBufferParamInfoByIndices(QSSGRenderBackendShaderProgramObject po,quint32 count,quint32 * indices,QSSGRenderShaderDataType * type,qint32 * size,qint32 * offset)1911 void QSSGRenderBackendGLBase::getConstantBufferParamInfoByIndices(QSSGRenderBackendShaderProgramObject po,
1912                                                                     quint32 count,
1913                                                                     quint32 *indices,
1914                                                                     QSSGRenderShaderDataType *type,
1915                                                                     qint32 *size,
1916                                                                     qint32 *offset)
1917 {
1918     // needs GL3 and above
1919     Q_UNUSED(po)
1920     Q_UNUSED(count)
1921     Q_UNUSED(indices)
1922     Q_UNUSED(type)
1923     Q_UNUSED(size)
1924     Q_UNUSED(offset)
1925 
1926     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1927 }
1928 
programSetConstantBlock(QSSGRenderBackendShaderProgramObject po,quint32 blockIndex,quint32 binding)1929 void QSSGRenderBackendGLBase::programSetConstantBlock(QSSGRenderBackendShaderProgramObject po, quint32 blockIndex, quint32 binding)
1930 {
1931     // needs GL3 and above
1932     Q_UNUSED(po)
1933     Q_UNUSED(blockIndex)
1934     Q_UNUSED(binding)
1935 
1936     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1937 }
1938 
programSetConstantBuffer(quint32 index,QSSGRenderBackendBufferObject bo)1939 void QSSGRenderBackendGLBase::programSetConstantBuffer(quint32 index, QSSGRenderBackendBufferObject bo)
1940 {
1941     // needs GL3 and above
1942     Q_UNUSED(index)
1943     Q_UNUSED(bo)
1944 
1945     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1946 }
1947 
getStorageBufferCount(QSSGRenderBackendShaderProgramObject po)1948 qint32 QSSGRenderBackendGLBase::getStorageBufferCount(QSSGRenderBackendShaderProgramObject po)
1949 {
1950     // needs GL4 and above
1951     Q_UNUSED(po)
1952 
1953     return 0;
1954 }
1955 
getStorageBufferInfoByID(QSSGRenderBackendShaderProgramObject po,quint32 id,quint32 nameBufSize,qint32 * paramCount,qint32 * bufferSize,qint32 * length,char * nameBuf)1956 qint32 QSSGRenderBackendGLBase::getStorageBufferInfoByID(QSSGRenderBackendShaderProgramObject po,
1957                                                            quint32 id,
1958                                                            quint32 nameBufSize,
1959                                                            qint32 *paramCount,
1960                                                            qint32 *bufferSize,
1961                                                            qint32 *length,
1962                                                            char *nameBuf)
1963 {
1964     // needs GL4 and above
1965     Q_UNUSED(po)
1966     Q_UNUSED(id)
1967     Q_UNUSED(nameBufSize)
1968     Q_UNUSED(paramCount)
1969     Q_UNUSED(bufferSize)
1970     Q_UNUSED(length)
1971     Q_UNUSED(nameBuf)
1972 
1973     qCCritical(RENDER_INVALID_OPERATION) << QObject::tr("Unsupported method: ") << __FUNCTION__;
1974 
1975     return -1;
1976 }
1977 
programSetStorageBuffer(quint32 index,QSSGRenderBackendBufferObject bo)1978 void QSSGRenderBackendGLBase::programSetStorageBuffer(quint32 index, QSSGRenderBackendBufferObject bo)
1979 {
1980     // needs GL4 and above
1981     Q_UNUSED(index)
1982     Q_UNUSED(bo)
1983 }
1984 
setConstantValue(QSSGRenderBackendShaderProgramObject,quint32 id,QSSGRenderShaderDataType type,qint32 count,const void * value,bool transpose)1985 void QSSGRenderBackendGLBase::setConstantValue(QSSGRenderBackendShaderProgramObject,
1986                                                  quint32 id,
1987                                                  QSSGRenderShaderDataType type,
1988                                                  qint32 count,
1989                                                  const void *value,
1990                                                  bool transpose)
1991 {
1992     GLenum glType = GLConversion::fromPropertyDataTypesToShaderGL(type);
1993 
1994     switch (glType) {
1995     case GL_FLOAT:
1996         GL_CALL_FUNCTION(glUniform1fv(GLint(id), count, reinterpret_cast<const GLfloat *>(value)));
1997         break;
1998     case GL_FLOAT_VEC2:
1999         GL_CALL_FUNCTION(glUniform2fv(GLint(id), count, reinterpret_cast<const GLfloat *>(value)));
2000         break;
2001     case GL_FLOAT_VEC3:
2002         GL_CALL_FUNCTION(glUniform3fv(GLint(id), count, reinterpret_cast<const GLfloat *>(value)));
2003         break;
2004     case GL_FLOAT_VEC4:
2005         GL_CALL_FUNCTION(glUniform4fv(GLint(id), count, reinterpret_cast<const GLfloat *>(value)));
2006         break;
2007     case GL_INT:
2008         GL_CALL_FUNCTION(glUniform1iv(GLint(id), count, reinterpret_cast<const GLint *>(value)));
2009         break;
2010     case GL_BOOL: {
2011         const GLint boolValue = value ? *reinterpret_cast<const bool *>(value) : false;
2012         GL_CALL_FUNCTION(glUniform1iv(GLint(id), count, &boolValue));
2013     } break;
2014     case GL_INT_VEC2:
2015     case GL_BOOL_VEC2:
2016         GL_CALL_FUNCTION(glUniform2iv(GLint(id), count, reinterpret_cast<const GLint *>(value)));
2017         break;
2018     case GL_INT_VEC3:
2019     case GL_BOOL_VEC3:
2020         GL_CALL_FUNCTION(glUniform3iv(GLint(id), count, reinterpret_cast<const GLint *>(value)));
2021         break;
2022     case GL_INT_VEC4:
2023     case GL_BOOL_VEC4:
2024         GL_CALL_FUNCTION(glUniform4iv(GLint(id), count, reinterpret_cast<const GLint *>(value)));
2025         break;
2026     case GL_FLOAT_MAT3:
2027         GL_CALL_FUNCTION(glUniformMatrix3fv(GLint(id), count, transpose, reinterpret_cast<const GLfloat *>(value)));
2028         break;
2029     case GL_FLOAT_MAT4:
2030         GL_CALL_FUNCTION(glUniformMatrix4fv(GLint(id), count, transpose, reinterpret_cast<const GLfloat *>(value)));
2031         break;
2032     case GL_IMAGE_2D:
2033     case GL_SAMPLER_2D:
2034     case GL_SAMPLER_2D_SHADOW:
2035     case GL_SAMPLER_CUBE: {
2036         if (count > 1) {
2037             const GLint *sampler = reinterpret_cast<const GLint *>(value);
2038             GL_CALL_FUNCTION(glUniform1iv(GLint(id), count, sampler));
2039         } else {
2040             const GLint sampler = *reinterpret_cast<const GLint *>(value);
2041             GL_CALL_FUNCTION(glUniform1i(GLint(id), sampler));
2042         }
2043     } break;
2044     default:
2045         qCCritical(RENDER_INTERNAL_ERROR, "Unknown shader type format %d", int(type));
2046         Q_ASSERT(false);
2047         break;
2048     }
2049 }
2050 
draw(QSSGRenderDrawMode drawMode,quint32 start,quint32 count)2051 void QSSGRenderBackendGLBase::draw(QSSGRenderDrawMode drawMode, quint32 start, quint32 count)
2052 {
2053     GL_CALL_FUNCTION(glDrawArrays(m_conversion.fromDrawModeToGL(drawMode, m_backendSupport.caps.bits.bTessellationSupported), GLint(start), GLsizei(count)));
2054 }
2055 
drawIndexed(QSSGRenderDrawMode drawMode,quint32 count,QSSGRenderComponentType type,const void * indices)2056 void QSSGRenderBackendGLBase::drawIndexed(QSSGRenderDrawMode drawMode,
2057                                             quint32 count,
2058                                             QSSGRenderComponentType type,
2059                                             const void *indices)
2060 {
2061     GL_CALL_FUNCTION(glDrawElements(m_conversion.fromDrawModeToGL(drawMode, m_backendSupport.caps.bits.bTessellationSupported),
2062                                     GLint(count),
2063                                     m_conversion.fromIndexBufferComponentsTypesToGL(type),
2064                                     indices));
2065 }
2066 
readPixel(QSSGRenderBackendRenderTargetObject,qint32 x,qint32 y,qint32 width,qint32 height,QSSGRenderReadPixelFormat inFormat,QSSGByteRef pixels)2067 void QSSGRenderBackendGLBase::readPixel(QSSGRenderBackendRenderTargetObject /* rto */,
2068                                           qint32 x,
2069                                           qint32 y,
2070                                           qint32 width,
2071                                           qint32 height,
2072                                           QSSGRenderReadPixelFormat inFormat,
2073                                           QSSGByteRef pixels)
2074 {
2075     GLuint glFormat;
2076     GLuint glType;
2077     if (GLConversion::fromReadPixelsToGlFormatAndType(inFormat, &glFormat, &glType)) {
2078         GL_CALL_FUNCTION(glReadPixels(x, y, width, height, glFormat, glType, pixels));
2079     }
2080 }
2081 
2082 ///< private calls
getShadingLanguageVersionString()2083 const char *QSSGRenderBackendGLBase::getShadingLanguageVersionString()
2084 {
2085     const GLubyte *retval = GL_CALL_FUNCTION(glGetString(GL_SHADING_LANGUAGE_VERSION));
2086     if (retval == nullptr)
2087         return "";
2088 
2089     return reinterpret_cast<const char *>(retval);
2090 }
2091 
getVersionString()2092 const char *QSSGRenderBackendGLBase::getVersionString()
2093 {
2094     const GLubyte *retval = GL_CALL_FUNCTION(glGetString(GL_VERSION));
2095     if (retval == nullptr)
2096         return "";
2097 
2098     return reinterpret_cast<const char *>(retval);
2099 }
2100 
getVendorString()2101 const char *QSSGRenderBackendGLBase::getVendorString()
2102 {
2103     const GLubyte *retval = GL_CALL_FUNCTION(glGetString(GL_VENDOR));
2104     if (retval == nullptr)
2105         return "";
2106 
2107     return reinterpret_cast<const char *>(retval);
2108 }
2109 
getRendererString()2110 const char *QSSGRenderBackendGLBase::getRendererString()
2111 {
2112     const GLubyte *retval = GL_CALL_FUNCTION(glGetString(GL_RENDERER));
2113     if (retval == nullptr)
2114         return "";
2115 
2116     return reinterpret_cast<const char *>(retval);
2117 }
2118 
getExtensionString()2119 const char *QSSGRenderBackendGLBase::getExtensionString()
2120 {
2121     const GLubyte *retval = GL_CALL_FUNCTION(glGetString(GL_EXTENSIONS));
2122     if (retval == nullptr)
2123         return "";
2124 
2125     return reinterpret_cast<const char *>(retval);
2126 }
2127 
2128 /**
2129  * @brief This function inspects the various strings to setup
2130  *		  HW capabilities of the device.
2131  *		  We can do a lot of smart things here based on GL version
2132  *		  renderer string and vendor.
2133  *
2134  * @return No return
2135  */
setAndInspectHardwareCaps()2136 void QSSGRenderBackendGLBase::setAndInspectHardwareCaps()
2137 {
2138     QByteArray apiVersion(getVersionString());
2139     qCInfo(RENDER_TRACE_INFO, "GL version: %s", apiVersion.constData());
2140 
2141     // we assume all GLES versions running on mobile with shared memory
2142     // this means framebuffer blits are slow and should be optimized or avoided
2143     if (!apiVersion.contains("OpenGL ES")) {
2144         // no ES device
2145         m_backendSupport.caps.bits.bFastBlitsSupported = true;
2146     }
2147 }
2148 
2149 QT_END_NAMESPACE
2150