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/qssgrenderbackendgl3_p.h>
32 #include <QtQuick3DRender/private/qssgrenderbackendinputassemblergl_p.h>
33 #include <QtQuick3DRender/private/qssgrenderbackendrenderstatesgl_p.h>
34 #include <QtQuick3DRender/private/qssgrenderbackendshaderprogramgl_p.h>
35 #include <QtQuick3DRender/private/qssgopenglextensions_p.h>
36
37 QT_BEGIN_NAMESPACE
38
39 #ifdef RENDER_BACKEND_LOG_GL_ERRORS
40 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError(#x, __FILE__, __LINE__)
41 #else
42 #define RENDER_LOG_ERROR_PARAMS(x) checkGLError()
43 #endif
44
45 #define GL_CALL_EXTRA_FUNCTION(x) \
46 m_glExtraFunctions->x; \
47 RENDER_LOG_ERROR_PARAMS(x);
48
49 #if defined(QT_OPENGL_ES)
50 #define GL_CALL_TIMER_EXT(x) \
51 m_QSSGExtensions->x; \
52 RENDER_LOG_ERROR_PARAMS(x);
53 #define GL_CALL_TESSELATION_EXT(x) \
54 m_QSSGExtensions->x; \
55 RENDER_LOG_ERROR_PARAMS(x);
56 #else
57 #define GL_CALL_TIMER_EXT(x) \
58 m_timerExtension->x; \
59 RENDER_LOG_ERROR_PARAMS(x);
60 #define GL_CALL_TESSELATION_EXT(x) \
61 m_tessellationShader->x; \
62 RENDER_LOG_ERROR_PARAMS(x);
63 #define GL_CALL_MULTISAMPLE_EXT(x) \
64 m_multiSample->x; \
65 RENDER_LOG_ERROR_PARAMS(x);
66 #endif
67
68 #ifndef GL_PATCH_VERTICES
69 #define GL_PATCH_VERTICES 0x8E72
70 #endif
71
72 namespace QSSGGlExtStrings {
extsAstcHDR()73 QByteArray extsAstcHDR()
74 {
75 return QByteArrayLiteral("GL_KHR_texture_compression_astc_hdr");
76 }
extsAstcLDR()77 QByteArray extsAstcLDR()
78 {
79 return QByteArrayLiteral("GL_KHR_texture_compression_astc_ldr");
80 }
81 }
82
83 /// constructor
QSSGRenderBackendGL3Impl(const QSurfaceFormat & format)84 QSSGRenderBackendGL3Impl::QSSGRenderBackendGL3Impl(const QSurfaceFormat &format) : QSSGRenderBackendGLBase(format)
85 {
86 // clear support bits
87 m_backendSupport.caps.u32Values = 0;
88
89 // get extension count
90 GLint numExtensions = 0;
91 GL_CALL_EXTRA_FUNCTION(glGetIntegerv(GL_NUM_EXTENSIONS, &numExtensions));
92
93 QByteArray extensionBuffer;
94
95 for (qint32 i = 0; i < numExtensions; i++) {
96 const GLubyte *glExt = GL_CALL_EXTRA_FUNCTION(glGetStringi(GL_EXTENSIONS, GLuint(i)));
97 const QByteArray extensionString(reinterpret_cast<const char *>(glExt));
98
99 m_extensions.push_back(extensionString);
100
101 if (extensionBuffer.size())
102 extensionBuffer.append(" ");
103 extensionBuffer.append(extensionString);
104
105 // search for extension
106 if (!m_backendSupport.caps.bits.bDXTImagesSupported
107 && (QSSGGlExtStrings::exts3tc().compare(extensionString) == 0
108 || QSSGGlExtStrings::extsdxt().compare(extensionString) == 0)) {
109 m_backendSupport.caps.bits.bDXTImagesSupported = true;
110 } else if (!m_backendSupport.caps.bits.bAnistropySupported && QSSGGlExtStrings::extsAniso().compare(extensionString) == 0) {
111 m_backendSupport.caps.bits.bAnistropySupported = true;
112 } else if (!m_backendSupport.caps.bits.bFPRenderTargetsSupported
113 && QSSGGlExtStrings::extsFPRenderTarget().compare(extensionString) == 0) {
114 m_backendSupport.caps.bits.bFPRenderTargetsSupported = true;
115 } else if (!m_backendSupport.caps.bits.bTimerQuerySupported
116 && QSSGGlExtStrings::extsTimerQuery().compare(extensionString) == 0) {
117 m_backendSupport.caps.bits.bTimerQuerySupported = true;
118 } else if (!m_backendSupport.caps.bits.bGPUShader5ExtensionSupported
119 && QSSGGlExtStrings::extsGpuShader5().compare(extensionString) == 0) {
120 m_backendSupport.caps.bits.bGPUShader5ExtensionSupported = true;
121 }
122 }
123
124 qCInfo(RENDER_TRACE_INFO, "OpenGL extensions: %s", extensionBuffer.constData());
125
126 // texture swizzle is always true
127 m_backendSupport.caps.bits.bTextureSwizzleSupported = true;
128 // depthstencil renderbuffer support is always true
129 m_backendSupport.caps.bits.bDepthStencilSupported = true;
130 // constant buffers support is always true
131 m_backendSupport.caps.bits.bConstantBufferSupported = true;
132 m_backendSupport.caps.bits.bStandardDerivativesSupported = true;
133 m_backendSupport.caps.bits.bVertexArrayObjectSupported = true;
134 m_backendSupport.caps.bits.bTextureLodSupported = true;
135
136 if (!isESCompatible()) {
137 // render to float textures is always supported on none ES systems which support >=GL3
138 m_backendSupport.caps.bits.bFPRenderTargetsSupported = true;
139 // multisampled texture is always supported on none ES systems which support >=GL3
140 m_backendSupport.caps.bits.bMsTextureSupported = true;
141 // timer queries are always supported on none ES systems which support >=GL3
142 m_backendSupport.caps.bits.bTimerQuerySupported = true;
143 }
144
145 // query hardware
146 GL_CALL_EXTRA_FUNCTION(glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &m_maxAttribCount));
147
148 // internal state tracker
149 m_currentMiscState = new QSSGRenderBackendMiscStateGL();
150
151 // finally setup caps based on device
152 setAndInspectHardwareCaps();
153
154 // Initialize extensions
155 #if defined(QT_OPENGL_ES_2)
156 m_QSSGExtensions = new QSSGOpenGLES2Extensions;
157 m_QSSGExtensions->initializeOpenGLFunctions();
158 #else
159 m_timerExtension = new QOpenGLExtension_ARB_timer_query;
160 m_timerExtension->initializeOpenGLFunctions();
161 m_tessellationShader = new QOpenGLExtension_ARB_tessellation_shader;
162 m_tessellationShader->initializeOpenGLFunctions();
163 m_multiSample = new QOpenGLExtension_ARB_texture_multisample;
164 m_multiSample->initializeOpenGLFunctions();
165 m_QSSGExtensions = new QSSGOpenGLExtensions;
166 m_QSSGExtensions->initializeOpenGLFunctions();
167 #endif
168 }
169 /// destructor
~QSSGRenderBackendGL3Impl()170 QSSGRenderBackendGL3Impl::~QSSGRenderBackendGL3Impl()
171 {
172 delete m_currentMiscState;
173 #if !defined(QT_OPENGL_ES_2)
174 delete m_timerExtension;
175 delete m_tessellationShader;
176 delete m_multiSample;
177 #endif
178 delete m_QSSGExtensions;
179 }
180
setMultisampledTextureData2D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 samples,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,bool fixedsamplelocations)181 void QSSGRenderBackendGL3Impl::setMultisampledTextureData2D(QSSGRenderBackendTextureObject to,
182 QSSGRenderTextureTargetType target,
183 qint32 samples,
184 QSSGRenderTextureFormat internalFormat,
185 qint32 width,
186 qint32 height,
187 bool fixedsamplelocations)
188 {
189 // Not supported by ES 3 yet
190 #if defined(QT_OPENGL_ES)
191 Q_UNUSED(to)
192 Q_UNUSED(target)
193 Q_UNUSED(samples)
194 Q_UNUSED(internalFormat)
195 Q_UNUSED(width)
196 Q_UNUSED(height)
197 Q_UNUSED(fixedsamplelocations)
198 #else
199 GLuint texID = HandleToID_cast(GLuint, quintptr, to);
200 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
201 setActiveTexture(GL_TEXTURE0);
202 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
203
204 QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
205 internalFormat = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), internalFormat, swizzleMode);
206
207 GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
208
209 if (internalFormat.isUncompressedTextureFormat())
210 GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
211 else if (internalFormat.isDepthTextureFormat())
212 GLConversion::fromDepthTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
213
214 GL_CALL_MULTISAMPLE_EXT(
215 glTexImage2DMultisample(glTarget, GLsizei(samples), GLint(glInternalFormat), GLsizei(width), GLsizei(height), fixedsamplelocations));
216
217 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
218 #endif
219 }
220
setTextureData3D(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 level,QSSGRenderTextureFormat internalFormat,qint32 width,qint32 height,qint32 depth,qint32 border,QSSGRenderTextureFormat format,QSSGByteView hostData)221 void QSSGRenderBackendGL3Impl::setTextureData3D(QSSGRenderBackendTextureObject to,
222 QSSGRenderTextureTargetType target,
223 qint32 level,
224 QSSGRenderTextureFormat internalFormat,
225 qint32 width,
226 qint32 height,
227 qint32 depth,
228 qint32 border,
229 QSSGRenderTextureFormat format,
230 QSSGByteView hostData)
231 {
232 GLuint texID = HandleToID_cast(GLuint, quintptr, to);
233 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
234 setActiveTexture(GL_TEXTURE0);
235 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
236 bool conversionRequired = format != internalFormat;
237
238 QSSGRenderTextureSwizzleMode swizzleMode = QSSGRenderTextureSwizzleMode::NoSwizzle;
239 internalFormat = GLConversion::replaceDeprecatedTextureFormat(getRenderContextType(), internalFormat, swizzleMode);
240
241 GLenum glformat = 0, glInternalFormat = 0, gltype = GL_UNSIGNED_BYTE;
242
243 if (internalFormat.isUncompressedTextureFormat())
244 GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), internalFormat, glformat, gltype, glInternalFormat);
245
246 if (conversionRequired) {
247 GLenum dummy;
248 GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, dummy);
249 } else if (internalFormat.isCompressedTextureFormat()) {
250 GLConversion::fromUncompressedTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
251 glInternalFormat = GLConversion::fromCompressedTextureFormatToGL(internalFormat);
252 } else if (format.isDepthTextureFormat()) {
253 GLConversion::fromDepthTextureFormatToGL(getRenderContextType(), format, glformat, gltype, glInternalFormat);
254 }
255
256 GL_CALL_EXTRA_FUNCTION(
257 glTexImage3D(glTarget, level, GLint(glInternalFormat), GLsizei(width), GLsizei(height), GLsizei(depth), border, glformat, gltype, hostData));
258
259 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
260 }
261
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)262 void QSSGRenderBackendGL3Impl::updateSampler(QSSGRenderBackendSamplerObject /* so */,
263 QSSGRenderTextureTargetType target,
264 QSSGRenderTextureMinifyingOp minFilter,
265 QSSGRenderTextureMagnifyingOp magFilter,
266 QSSGRenderTextureCoordOp wrapS,
267 QSSGRenderTextureCoordOp wrapT,
268 QSSGRenderTextureCoordOp wrapR,
269 float minLod,
270 float maxLod,
271 float lodBias,
272 QSSGRenderTextureCompareMode compareMode,
273 QSSGRenderTextureCompareOp compareFunc,
274 float anisotropy,
275 float *borderColor)
276 {
277
278 // Satisfy the compiler
279 // These are not available in GLES 3 and we don't use them right now
280 Q_ASSERT(qFuzzyIsNull(lodBias));
281 Q_ASSERT(!borderColor);
282 Q_UNUSED(lodBias)
283 Q_UNUSED(borderColor)
284
285 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
286
287 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MIN_FILTER, GLint(m_conversion.fromTextureMinifyingOpToGL(minFilter))));
288 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MAG_FILTER, GLint(m_conversion.fromTextureMagnifyingOpToGL(magFilter))));
289 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_S, GLint(m_conversion.fromTextureCoordOpToGL(wrapS))));
290 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_T, GLint(m_conversion.fromTextureCoordOpToGL(wrapT))));
291 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_WRAP_R, GLint(m_conversion.fromTextureCoordOpToGL(wrapR))));
292 GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MIN_LOD, minLod));
293 GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MAX_LOD, maxLod));
294 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_COMPARE_MODE, GLint(m_conversion.fromTextureCompareModeToGL(compareMode))));
295 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_COMPARE_FUNC, GLint(m_conversion.fromTextureCompareFuncToGL(compareFunc))));
296
297 if (m_backendSupport.caps.bits.bAnistropySupported) {
298 GL_CALL_EXTRA_FUNCTION(glTexParameterf(glTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy));
299 }
300 }
301
updateTextureObject(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,qint32 baseLevel,qint32 maxLevel)302 void QSSGRenderBackendGL3Impl::updateTextureObject(QSSGRenderBackendTextureObject to,
303 QSSGRenderTextureTargetType target,
304 qint32 baseLevel,
305 qint32 maxLevel)
306 {
307 Q_UNUSED(to)
308
309 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
310
311 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_BASE_LEVEL, baseLevel));
312 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_MAX_LEVEL, maxLevel));
313 }
314
updateTextureSwizzle(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,QSSGRenderTextureSwizzleMode swizzleMode)315 void QSSGRenderBackendGL3Impl::updateTextureSwizzle(QSSGRenderBackendTextureObject to,
316 QSSGRenderTextureTargetType target,
317 QSSGRenderTextureSwizzleMode swizzleMode)
318 {
319 Q_UNUSED(to)
320 if (m_backendSupport.caps.bits.bTextureSwizzleSupported) {
321 GLint glSwizzle[4];
322 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
323 GLConversion::NVRenderConvertSwizzleModeToGL(swizzleMode, glSwizzle);
324 #if defined(QT_OPENGL_ES)
325 // since ES3 spec has no GL_TEXTURE_SWIZZLE_RGBA set it separately
326 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_R, glSwizzle[0]));
327 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_G, glSwizzle[1]));
328 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_B, glSwizzle[2]));
329 GL_CALL_EXTRA_FUNCTION(glTexParameteri(glTarget, GL_TEXTURE_SWIZZLE_A, glSwizzle[3]));
330 #else
331 GL_CALL_EXTRA_FUNCTION(glTexParameteriv(glTarget, GL_TEXTURE_SWIZZLE_RGBA, glSwizzle));
332 #endif
333 }
334 }
335
getDepthBits() const336 qint32 QSSGRenderBackendGL3Impl::getDepthBits() const
337 {
338 qint32 depthBits;
339 GL_CALL_EXTRA_FUNCTION(
340 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE, &depthBits));
341
342 return depthBits;
343 }
344
getStencilBits() const345 qint32 QSSGRenderBackendGL3Impl::getStencilBits() const
346 {
347 qint32 stencilBits;
348 GL_CALL_EXTRA_FUNCTION(
349 glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE, &stencilBits));
350
351 return stencilBits;
352 }
353
generateMipMaps(QSSGRenderBackendTextureObject to,QSSGRenderTextureTargetType target,QSSGRenderHint)354 void QSSGRenderBackendGL3Impl::generateMipMaps(QSSGRenderBackendTextureObject to,
355 QSSGRenderTextureTargetType target,
356 QSSGRenderHint /*genType*/)
357 {
358 GLuint texID = HandleToID_cast(GLuint, quintptr, to);
359 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
360 setActiveTexture(GL_TEXTURE0);
361 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID));
362 GL_CALL_EXTRA_FUNCTION(glGenerateMipmap(glTarget));
363 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, 0));
364 }
365
getShadingLanguageVersion()366 QByteArray QSSGRenderBackendGL3Impl::getShadingLanguageVersion()
367 {
368 Q_ASSERT(m_format.majorVersion() >= 3);
369
370 QByteArray ver("#version 300");
371 if (m_format.majorVersion() == 3)
372 ver[10] = '0' + char(m_format.minorVersion());
373 else if (m_format.majorVersion() > 3)
374 ver[10] = '3';
375
376 if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
377 ver.append(" es");
378
379 return ver.append("\n");
380 }
381
getRenderContextType() const382 QSSGRenderContextType QSSGRenderBackendGL3Impl::getRenderContextType() const
383 {
384 Q_ASSERT(m_format.majorVersion() >= 3);
385
386 if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
387 if (m_format.minorVersion() >= 1)
388 return QSSGRenderContextType::GLES3PLUS;
389
390 return QSSGRenderContextType::GLES3;
391 }
392
393 return QSSGRenderContextType::GL3;
394 }
395
setInputAssembler(QSSGRenderBackendInputAssemblerObject iao,QSSGRenderBackendShaderProgramObject po)396 bool QSSGRenderBackendGL3Impl::setInputAssembler(QSSGRenderBackendInputAssemblerObject iao, QSSGRenderBackendShaderProgramObject po)
397 {
398 if (iao == nullptr) {
399 // unbind and return;
400 GL_CALL_EXTRA_FUNCTION(glBindVertexArray(0));
401 return true;
402 }
403
404 QSSGRenderBackendInputAssemblerGL *inputAssembler = reinterpret_cast<QSSGRenderBackendInputAssemblerGL *>(iao);
405 QSSGRenderBackendAttributeLayoutGL *attribLayout = inputAssembler->m_attribLayout;
406 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
407 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
408 QSSGDataRef<QSSGRenderBackendShaderInputEntryGL> shaderAttribBuffer;
409 if (pProgram->m_shaderInput)
410 shaderAttribBuffer = pProgram->m_shaderInput->m_shaderInputEntries;
411
412 // Need to be careful with the attributes. shaderAttribBuffer contains
413 // whatever glGetActiveAttrib() returns. There can however be differences
414 // between OpenGL implementations: some will optimize out unused
415 // attributes, while others could report all attributes as active,
416 // regardless of them being used in practice or not.
417 //
418 // In addition, not binding any data to an attribute is not an error with
419 // OpenGL, and in fact is unavoidable when a model, for example, has no UV
420 // coordinates (and associated data, such as tangetst and binormals), but
421 // is then used with a shader with lighting, shadows, and such. This needs
422 // to be handled gracefully. It can lead to incorrect rendering but the
423 // object still needs to be there, without bailing out or flooding the
424 // output with warnings.
425
426 // if (attribLayout->m_layoutAttribEntries.size() < shaderAttribBuffer.size())
427
428 if (inputAssembler->m_vertexbufferHandles.size() <= attribLayout->m_maxInputSlot)
429 return false;
430
431 if (inputAssembler->m_vaoID == 0) {
432 // generate vao
433 GL_CALL_EXTRA_FUNCTION(glGenVertexArrays(1, &inputAssembler->m_vaoID));
434 Q_ASSERT(inputAssembler->m_vaoID);
435 }
436
437 // set patch parameter count if changed
438 if (m_backendSupport.caps.bits.bTessellationSupported && m_currentMiscState->m_patchVertexCount != inputAssembler->m_patchVertexCount) {
439 m_currentMiscState->m_patchVertexCount = inputAssembler->m_patchVertexCount;
440 #if defined(QT_OPENGL_ES)
441 GL_CALL_TESSELATION_EXT(glPatchParameteriEXT(GL_PATCH_VERTICES, inputAssembler->m_patchVertexCount));
442 #else
443 GL_CALL_TESSELATION_EXT(glPatchParameteri(GL_PATCH_VERTICES, GLint(inputAssembler->m_patchVertexCount)));
444 #endif
445 }
446
447 if (inputAssembler->m_cachedShaderHandle != programID) {
448 GL_CALL_EXTRA_FUNCTION(glBindVertexArray(inputAssembler->m_vaoID));
449 inputAssembler->m_cachedShaderHandle = programID;
450
451 for (const auto &attrib : qAsConst(shaderAttribBuffer)) {
452 QSSGRenderBackendLayoutEntryGL *entry = attribLayout->getEntryByName(attrib.m_attribName);
453
454 if (entry) {
455 QSSGRenderBackendLayoutEntryGL &entryData(*entry);
456 if (Q_UNLIKELY(entryData.m_type != attrib.m_type || entryData.m_numComponents != attrib.m_numComponents)) {
457 qCCritical(RENDER_INVALID_OPERATION, "Attrib %s doesn't match vertex layout", attrib.m_attribName.constData());
458 Q_ASSERT(false);
459 return false;
460 }
461 entryData.m_attribIndex = attrib.m_attribLocation;
462 } else {
463 qCWarning(RENDER_WARNING, "Failed to bind attribute %s", attrib.m_attribName.constData());
464 }
465 }
466
467 // disable max possible used first
468 // this is currently sufficient since we always re-arrange input attributes from 0
469 for (int i = 0; i < attribLayout->m_layoutAttribEntries.size(); i++)
470 GL_CALL_EXTRA_FUNCTION(glDisableVertexAttribArray(GLuint(i)));
471
472 // setup all attribs
473 GLuint boundArrayBufferId = 0; // 0 means unbound
474 for (int idx = 0; idx != shaderAttribBuffer.size(); ++idx) {
475 QSSGRenderBackendLayoutEntryGL *entry = attribLayout->getEntryByName(shaderAttribBuffer[idx].m_attribName);
476 if (entry) {
477 const QSSGRenderBackendLayoutEntryGL &entryData(*entry);
478 GLuint id = HandleToID_cast(GLuint, quintptr, inputAssembler->m_vertexbufferHandles.mData[entryData.m_inputSlot]);
479 if (boundArrayBufferId != id) {
480 GL_CALL_EXTRA_FUNCTION(glBindBuffer(GL_ARRAY_BUFFER, id));
481 boundArrayBufferId = id;
482 }
483 GL_CALL_EXTRA_FUNCTION(glEnableVertexAttribArray(entryData.m_attribIndex));
484 GLuint offset = inputAssembler->m_offsets.at(int(entryData.m_inputSlot));
485 GLuint stride = inputAssembler->m_strides.at(int(entryData.m_inputSlot));
486 GL_CALL_EXTRA_FUNCTION(glVertexAttribPointer(entryData.m_attribIndex,
487 GLint(entryData.m_numComponents),
488 GL_FLOAT,
489 GL_FALSE,
490 GLsizei(stride),
491 reinterpret_cast<const void *>(quintptr(entryData.m_offset + offset))));
492
493 } else {
494 GL_CALL_EXTRA_FUNCTION(glDisableVertexAttribArray(GLuint(idx)));
495 }
496 }
497
498 // setup index buffer.
499 if (inputAssembler->m_indexbufferHandle) {
500 GL_CALL_EXTRA_FUNCTION(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
501 HandleToID_cast(GLuint, quintptr, inputAssembler->m_indexbufferHandle)));
502 } else {
503 GL_CALL_EXTRA_FUNCTION(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
504 }
505 } else {
506 GL_CALL_EXTRA_FUNCTION(glBindVertexArray(inputAssembler->m_vaoID));
507 }
508 #ifdef _DEBUG
509 if (inputAssembler->m_vaoID) {
510 for (const auto &attrib : qAsConst(shaderAttribBuffer)) {
511 QSSGRenderBackendLayoutEntryGL *entry = attribLayout->getEntryByName(attrib.m_attribName);
512
513 if (entry) {
514 QSSGRenderBackendLayoutEntryGL &entryData(*entry);
515 if (entryData.m_type != attrib.m_type || entryData.m_numComponents != attrib.m_numComponents
516 || entryData.m_attribIndex != attrib.m_attribLocation) {
517 qCCritical(RENDER_INVALID_OPERATION, "Attrib %s doesn't match vertex layout", qPrintable(attrib.m_attribName));
518 Q_ASSERT(false);
519 }
520 } else {
521 qCWarning(RENDER_WARNING, "Failed to bind attribute %s", qPrintable(attrib.m_attribName));
522 }
523 }
524 }
525 #endif // _DEBUG
526
527 return true;
528 }
529
setDrawBuffers(QSSGRenderBackendRenderTargetObject rto,QSSGDataView<qint32> inDrawBufferSet)530 void QSSGRenderBackendGL3Impl::setDrawBuffers(QSSGRenderBackendRenderTargetObject rto, QSSGDataView<qint32> inDrawBufferSet)
531 {
532 Q_UNUSED(rto)
533
534 m_drawBuffersArray.clear();
535
536 for (int idx = 0, end = inDrawBufferSet.size(); idx < end; ++idx) {
537 if (inDrawBufferSet[idx] < 0)
538 m_drawBuffersArray.push_back(GL_NONE);
539 else
540 m_drawBuffersArray.push_back(GL_COLOR_ATTACHMENT0 + GLuint(inDrawBufferSet[idx]));
541 }
542
543 GL_CALL_EXTRA_FUNCTION(glDrawBuffers(m_drawBuffersArray.size(), m_drawBuffersArray.data()));
544 }
545
setReadBuffer(QSSGRenderBackendRenderTargetObject rto,QSSGReadFace inReadFace)546 void QSSGRenderBackendGL3Impl::setReadBuffer(QSSGRenderBackendRenderTargetObject rto, QSSGReadFace inReadFace)
547 {
548 Q_UNUSED(rto)
549
550 GL_CALL_EXTRA_FUNCTION(glReadBuffer(m_conversion.fromReadFacesToGL(inReadFace)));
551 }
552
renderTargetAttach(QSSGRenderBackendRenderTargetObject,QSSGRenderFrameBufferAttachment attachment,QSSGRenderBackendTextureObject to,qint32 level,qint32 layer)553 void QSSGRenderBackendGL3Impl::renderTargetAttach(QSSGRenderBackendRenderTargetObject,
554 QSSGRenderFrameBufferAttachment attachment,
555 QSSGRenderBackendTextureObject to,
556 qint32 level,
557 qint32 layer)
558 {
559 // rto must be the current render target
560 GLuint texID = HandleToID_cast(GLuint, quintptr, to);
561
562 GLenum glAttach = GLConversion::fromFramebufferAttachmentsToGL(attachment);
563
564 GL_CALL_EXTRA_FUNCTION(glFramebufferTextureLayer(GL_FRAMEBUFFER, glAttach, texID, level, layer))
565 }
566
setReadTarget(QSSGRenderBackendRenderTargetObject rto)567 void QSSGRenderBackendGL3Impl::setReadTarget(QSSGRenderBackendRenderTargetObject rto)
568 {
569 GLuint fboID = HandleToID_cast(GLuint, quintptr, rto);
570
571 GL_CALL_EXTRA_FUNCTION(glBindFramebuffer(GL_READ_FRAMEBUFFER, fboID));
572 }
573
blitFramebuffer(qint32 srcX0,qint32 srcY0,qint32 srcX1,qint32 srcY1,qint32 dstX0,qint32 dstY0,qint32 dstX1,qint32 dstY1,QSSGRenderClearFlags flags,QSSGRenderTextureMagnifyingOp filter)574 void QSSGRenderBackendGL3Impl::blitFramebuffer(qint32 srcX0,
575 qint32 srcY0,
576 qint32 srcX1,
577 qint32 srcY1,
578 qint32 dstX0,
579 qint32 dstY0,
580 qint32 dstX1,
581 qint32 dstY1,
582 QSSGRenderClearFlags flags,
583 QSSGRenderTextureMagnifyingOp filter)
584 {
585 GL_CALL_EXTRA_FUNCTION(glBlitFramebuffer(srcX0,
586 srcY0,
587 srcX1,
588 srcY1,
589 dstX0,
590 dstY0,
591 dstX1,
592 dstY1,
593 m_conversion.fromClearFlagsToGL(flags),
594 m_conversion.fromTextureMagnifyingOpToGL(filter)));
595 }
596
copyFramebufferTexture(qint32 srcX0,qint32 srcY0,qint32 width,qint32 height,qint32 dstX0,qint32 dstY0,QSSGRenderBackendTextureObject texture,QSSGRenderTextureTargetType target)597 void QSSGRenderBackendGL3Impl::copyFramebufferTexture(qint32 srcX0,
598 qint32 srcY0,
599 qint32 width,
600 qint32 height,
601 qint32 dstX0,
602 qint32 dstY0,
603 QSSGRenderBackendTextureObject texture,
604 QSSGRenderTextureTargetType target)
605 {
606 GLuint texID = HandleToID_cast(GLuint, quintptr, texture);
607 GLenum glTarget = GLConversion::fromTextureTargetToGL(target);
608 setActiveTexture(GL_TEXTURE0);
609 GL_CALL_EXTRA_FUNCTION(glBindTexture(glTarget, texID))
610 GL_CALL_EXTRA_FUNCTION(glCopyTexSubImage2D(GL_TEXTURE_2D, 0, srcX0, srcY0, dstX0, dstY0,
611 width, height))
612 }
613
mapBuffer(QSSGRenderBackendBufferObject,QSSGRenderBufferType bindFlags,size_t offset,size_t length,QSSGRenderBufferAccessFlags accessFlags)614 void *QSSGRenderBackendGL3Impl::mapBuffer(QSSGRenderBackendBufferObject,
615 QSSGRenderBufferType bindFlags,
616 size_t offset,
617 size_t length,
618 QSSGRenderBufferAccessFlags accessFlags)
619 {
620 void *ret = nullptr;
621 ret = GL_CALL_EXTRA_FUNCTION(glMapBufferRange(m_conversion.fromBindBufferFlagsToGL(bindFlags),
622 GLintptr(offset),
623 GLintptr(length),
624 m_conversion.fromBufferAccessBitToGL(accessFlags)));
625
626 return ret;
627 }
628
unmapBuffer(QSSGRenderBackendBufferObject,QSSGRenderBufferType bindFlags)629 bool QSSGRenderBackendGL3Impl::unmapBuffer(QSSGRenderBackendBufferObject, QSSGRenderBufferType bindFlags)
630 {
631 const GLboolean ret = GL_CALL_EXTRA_FUNCTION(glUnmapBuffer(m_conversion.fromBindBufferFlagsToGL(bindFlags)));
632 return (ret != 0);
633 }
634
getConstantBufferCount(QSSGRenderBackendShaderProgramObject po)635 qint32 QSSGRenderBackendGL3Impl::getConstantBufferCount(QSSGRenderBackendShaderProgramObject po)
636 {
637 Q_ASSERT(po);
638 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
639 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
640
641 GLint numUniformBuffers;
642 GL_CALL_EXTRA_FUNCTION(glGetProgramiv(programID, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBuffers));
643
644 return numUniformBuffers;
645 }
646
getConstantBufferInfoByID(QSSGRenderBackendShaderProgramObject po,quint32 id,quint32 nameBufSize,qint32 * paramCount,qint32 * bufferSize,qint32 * length,char * nameBuf)647 qint32 QSSGRenderBackendGL3Impl::getConstantBufferInfoByID(QSSGRenderBackendShaderProgramObject po,
648 quint32 id,
649 quint32 nameBufSize,
650 qint32 *paramCount,
651 qint32 *bufferSize,
652 qint32 *length,
653 char *nameBuf)
654 {
655 Q_ASSERT(po);
656 Q_ASSERT(length);
657 Q_ASSERT(nameBuf);
658
659 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
660 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
661 GLuint blockIndex = GL_INVALID_INDEX;
662
663 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockName(programID, id, GLsizei(nameBufSize), length, nameBuf));
664
665 if (*length > 0) {
666 blockIndex = GL_CALL_EXTRA_FUNCTION(glGetUniformBlockIndex(programID, nameBuf));
667 if (blockIndex != GL_INVALID_INDEX) {
668 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, blockIndex, GL_UNIFORM_BLOCK_DATA_SIZE, bufferSize));
669 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, blockIndex, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, paramCount));
670 }
671 }
672
673 return qint32(blockIndex);
674 }
675
getConstantBufferParamIndices(QSSGRenderBackendShaderProgramObject po,quint32 id,qint32 * indices)676 void QSSGRenderBackendGL3Impl::getConstantBufferParamIndices(QSSGRenderBackendShaderProgramObject po, quint32 id, qint32 *indices)
677 {
678 Q_ASSERT(po);
679 Q_ASSERT(indices);
680
681 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
682 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
683
684 if (indices) {
685 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformBlockiv(programID, id, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices));
686 }
687 }
688
getConstantBufferParamInfoByIndices(QSSGRenderBackendShaderProgramObject po,quint32 count,quint32 * indices,QSSGRenderShaderDataType * type,qint32 * size,qint32 * offset)689 void QSSGRenderBackendGL3Impl::getConstantBufferParamInfoByIndices(QSSGRenderBackendShaderProgramObject po,
690 quint32 count,
691 quint32 *indices,
692 QSSGRenderShaderDataType *type,
693 qint32 *size,
694 qint32 *offset)
695 {
696 Q_ASSERT(po);
697 Q_ASSERT(count && count <= INT32_MAX);
698 Q_ASSERT(indices);
699
700 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
701 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
702
703 if (count && indices) {
704 if (type) {
705 QVarLengthArray<qint32, 1024> glTypes(count);
706 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformsiv(programID, GLsizei(count), indices, GL_UNIFORM_TYPE, glTypes.data()));
707 // convert to UIC types
708 for (qint32 idx = 0; idx != qint32(count); ++idx)
709 type[idx] = GLConversion::fromShaderGLToPropertyDataTypes(GLenum(glTypes[idx]));
710 }
711 if (size)
712 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformsiv(programID, GLsizei(count), indices, GL_UNIFORM_SIZE, size));
713 if (offset)
714 GL_CALL_EXTRA_FUNCTION(glGetActiveUniformsiv(programID, GLsizei(count), indices, GL_UNIFORM_OFFSET, offset));
715 }
716 }
717
programSetConstantBlock(QSSGRenderBackendShaderProgramObject po,quint32 blockIndex,quint32 binding)718 void QSSGRenderBackendGL3Impl::programSetConstantBlock(QSSGRenderBackendShaderProgramObject po, quint32 blockIndex, quint32 binding)
719 {
720 QSSGRenderBackendShaderProgramGL *pProgram = reinterpret_cast<QSSGRenderBackendShaderProgramGL *>(po);
721 GLuint programID = static_cast<GLuint>(pProgram->m_programID);
722
723 GL_CALL_EXTRA_FUNCTION(glUniformBlockBinding(programID, blockIndex, binding));
724 }
725
programSetConstantBuffer(quint32 index,QSSGRenderBackendBufferObject bo)726 void QSSGRenderBackendGL3Impl::programSetConstantBuffer(quint32 index, QSSGRenderBackendBufferObject bo)
727 {
728 Q_ASSERT(bo);
729
730 GLuint bufID = HandleToID_cast(GLuint, quintptr, bo);
731 GL_CALL_EXTRA_FUNCTION(glBindBufferBase(GL_UNIFORM_BUFFER, index, bufID));
732 }
733
createQuery()734 QSSGRenderBackend::QSSGRenderBackendQueryObject QSSGRenderBackendGL3Impl::createQuery()
735 {
736 quint32 glQueryID = 0;
737
738 GL_CALL_EXTRA_FUNCTION(glGenQueries(1, &glQueryID));
739
740 return reinterpret_cast<QSSGRenderBackendQueryObject>(quintptr(glQueryID));
741 }
742
releaseQuery(QSSGRenderBackendQueryObject qo)743 void QSSGRenderBackendGL3Impl::releaseQuery(QSSGRenderBackendQueryObject qo)
744 {
745 GLuint queryID = HandleToID_cast(GLuint, quintptr, qo);
746
747 GL_CALL_EXTRA_FUNCTION(glDeleteQueries(1, &queryID));
748 }
749
beginQuery(QSSGRenderBackendQueryObject qo,QSSGRenderQueryType type)750 void QSSGRenderBackendGL3Impl::beginQuery(QSSGRenderBackendQueryObject qo, QSSGRenderQueryType type)
751 {
752 GLuint queryID = HandleToID_cast(GLuint, quintptr, qo);
753
754 GL_CALL_EXTRA_FUNCTION(glBeginQuery(m_conversion.fromQueryTypeToGL(type), queryID));
755 }
756
endQuery(QSSGRenderBackendQueryObject,QSSGRenderQueryType type)757 void QSSGRenderBackendGL3Impl::endQuery(QSSGRenderBackendQueryObject, QSSGRenderQueryType type)
758 {
759 GL_CALL_EXTRA_FUNCTION(glEndQuery(m_conversion.fromQueryTypeToGL(type)));
760 }
761
getQueryResult(QSSGRenderBackendQueryObject qo,QSSGRenderQueryResultType resultType,quint32 * params)762 void QSSGRenderBackendGL3Impl::getQueryResult(QSSGRenderBackendQueryObject qo,
763 QSSGRenderQueryResultType resultType,
764 quint32 *params)
765 {
766 GLuint queryID = HandleToID_cast(GLuint, quintptr, qo);
767
768 if (params)
769 GL_CALL_EXTRA_FUNCTION(glGetQueryObjectuiv(queryID, m_conversion.fromQueryResultTypeToGL(resultType), params));
770 }
771
getQueryResult(QSSGRenderBackendQueryObject qo,QSSGRenderQueryResultType resultType,quint64 * params)772 void QSSGRenderBackendGL3Impl::getQueryResult(QSSGRenderBackendQueryObject qo,
773 QSSGRenderQueryResultType resultType,
774 quint64 *params)
775 {
776 // TODO: params type!
777 if (m_backendSupport.caps.bits.bTimerQuerySupported) {
778 GLuint queryID = HandleToID_cast(GLuint, quintptr, qo);
779
780 if (params)
781 #if defined(QT_OPENGL_ES)
782 GL_CALL_TIMER_EXT(glGetQueryObjectui64vEXT(queryID, m_conversion.fromQueryResultTypeToGL(resultType), reinterpret_cast<GLuint64 *>(params)));
783 #else
784 GL_CALL_TIMER_EXT(glGetQueryObjectui64v(queryID, m_conversion.fromQueryResultTypeToGL(resultType), reinterpret_cast<GLuint64 *>(params)));
785 #endif
786 }
787 }
788
setQueryTimer(QSSGRenderBackendQueryObject qo)789 void QSSGRenderBackendGL3Impl::setQueryTimer(QSSGRenderBackendQueryObject qo)
790 {
791 if (m_backendSupport.caps.bits.bTimerQuerySupported) {
792 GLuint queryID = HandleToID_cast(GLuint, quintptr, qo);
793 #if defined(QT_OPENGL_ES)
794 GL_CALL_TIMER_EXT(glQueryCounterEXT(queryID, GL_TIMESTAMP));
795 #else
796 GL_CALL_TIMER_EXT(glQueryCounter(queryID, GL_TIMESTAMP));
797 #endif
798 }
799 }
800
createSync(QSSGRenderSyncType syncType,QSSGRenderSyncFlags)801 QSSGRenderBackend::QSSGRenderBackendSyncObject QSSGRenderBackendGL3Impl::createSync(QSSGRenderSyncType syncType,
802 QSSGRenderSyncFlags)
803 {
804 GLsync syncID = nullptr;
805
806 syncID = GL_CALL_EXTRA_FUNCTION(glFenceSync(m_conversion.fromSyncTypeToGL(syncType), 0));
807
808 return QSSGRenderBackendSyncObject(syncID);
809 }
810
releaseSync(QSSGRenderBackendSyncObject so)811 void QSSGRenderBackendGL3Impl::releaseSync(QSSGRenderBackendSyncObject so)
812 {
813 GLsync syncID = GLsync(so);
814
815 GL_CALL_EXTRA_FUNCTION(glDeleteSync(syncID));
816 }
817
waitSync(QSSGRenderBackendSyncObject so,QSSGRenderCommandFlushFlags,quint64)818 void QSSGRenderBackendGL3Impl::waitSync(QSSGRenderBackendSyncObject so, QSSGRenderCommandFlushFlags, quint64)
819 {
820 GLsync syncID = GLsync(so);
821
822 GL_CALL_EXTRA_FUNCTION(glWaitSync(syncID, 0, GL_TIMEOUT_IGNORED));
823 }
824
releaseInputAssembler(QSSGRenderBackendInputAssemblerObject iao)825 void QSSGRenderBackendGL3Impl::releaseInputAssembler(QSSGRenderBackendInputAssemblerObject iao)
826 {
827 QSSGRenderBackendInputAssemblerGL *inputAssembler = reinterpret_cast<QSSGRenderBackendInputAssemblerGL *>(iao);
828 GL_CALL_EXTRA_FUNCTION(glDeleteVertexArrays(1, &inputAssembler->m_vaoID));
829 delete inputAssembler;
830 }
831
832 QT_END_NAMESPACE
833
834
835