1/****************************************************************************
2**
3** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
4** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the Qt3D module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
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 Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "graphicscontext_p.h"
42
43#include <Qt3DRender/qgraphicsapifilter.h>
44#include <Qt3DRender/qparameter.h>
45#include <Qt3DRender/private/renderlogging_p.h>
46#include <Qt3DRender/private/shader_p.h>
47#include <Qt3DRender/private/material_p.h>
48#include <Qt3DRender/private/buffer_p.h>
49#include <Qt3DRender/private/attribute_p.h>
50#include <Qt3DRender/private/rendertarget_p.h>
51#include <Qt3DRender/private/nodemanagers_p.h>
52#include <Qt3DRender/private/buffermanager_p.h>
53#include <Qt3DRender/private/managers_p.h>
54#include <Qt3DRender/private/attachmentpack_p.h>
55#include <Qt3DRender/private/qbuffer_p.h>
56#include <Qt3DRender/private/attachmentpack_p.h>
57#include <Qt3DRender/private/qbuffer_p.h>
58#include <Qt3DRender/private/renderstateset_p.h>
59#include <QOpenGLShaderProgram>
60#include <glresourcemanagers_p.h>
61#include <graphicshelperinterface_p.h>
62#include <gltexture_p.h>
63#include <rendercommand_p.h>
64#include <renderer_p.h>
65#include <renderbuffer_p.h>
66#include <glshader_p.h>
67
68#if !defined(QT_OPENGL_ES_2)
69#include <QOpenGLFunctions_2_0>
70#include <QOpenGLFunctions_3_2_Core>
71#include <QOpenGLFunctions_3_3_Core>
72#include <QOpenGLFunctions_4_3_Core>
73#include <graphicshelpergl2_p.h>
74#include <graphicshelpergl3_2_p.h>
75#include <graphicshelpergl3_3_p.h>
76#include <graphicshelpergl4_p.h>
77#endif
78#include <graphicshelperes2_p.h>
79#include <graphicshelperes3_p.h>
80#include <graphicshelperes3_1_p.h>
81#include <graphicshelperes3_2_p.h>
82
83#include <QSurface>
84#include <QWindow>
85#include <QOpenGLTexture>
86#include <QOpenGLDebugLogger>
87
88QT_BEGIN_NAMESPACE
89
90#ifndef GL_READ_FRAMEBUFFER
91#define GL_READ_FRAMEBUFFER 0x8CA8
92#endif
93
94#ifndef GL_DRAW_FRAMEBUFFER
95#define GL_DRAW_FRAMEBUFFER 0x8CA9
96#endif
97
98#ifndef GL_MAX_IMAGE_UNITS
99#define GL_MAX_IMAGE_UNITS 0x8F38
100#endif
101
102namespace {
103
104QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
105{
106 switch (type) {
107 case Qt3DRender::QShaderProgram::Vertex: return QOpenGLShader::Vertex;
108 case Qt3DRender::QShaderProgram::TessellationControl: return QOpenGLShader::TessellationControl;
109 case Qt3DRender::QShaderProgram::TessellationEvaluation: return QOpenGLShader::TessellationEvaluation;
110 case Qt3DRender::QShaderProgram::Geometry: return QOpenGLShader::Geometry;
111 case Qt3DRender::QShaderProgram::Fragment: return QOpenGLShader::Fragment;
112 case Qt3DRender::QShaderProgram::Compute: return QOpenGLShader::Compute;
113 default: Q_UNREACHABLE();
114 }
115}
116
117} // anonymous namespace
118
119namespace Qt3DRender {
120namespace Render {
121namespace OpenGL {
122
123namespace {
124
125void logOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage)
126{
127 qDebug() << "OpenGL debug message:" << debugMessage;
128}
129
130} // anonymous
131
132GraphicsContext::GraphicsContext()
133 : m_initialized(false)
134 , m_supportsVAO(false)
135 , m_maxTextureUnits(0)
136 , m_maxImageUnits(0)
137 , m_defaultFBO(0)
138 , m_gl(nullptr)
139 , m_glHelper(nullptr)
140 , m_debugLogger(nullptr)
141 , m_currentVAO(nullptr)
142{
143}
144
145GraphicsContext::~GraphicsContext()
146{
147}
148
149void GraphicsContext::setOpenGLContext(QOpenGLContext* ctx)
150{
151 Q_ASSERT(ctx);
152 m_gl = ctx;
153}
154
155void GraphicsContext::initialize()
156{
157 m_initialized = true;
158
159 Q_ASSERT(m_gl);
160
161 m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, params: &m_maxTextureUnits);
162 qCDebug(Backend) << "context supports" << m_maxTextureUnits << "texture units";
163 m_gl->functions()->glGetIntegerv(GL_MAX_IMAGE_UNITS, params: &m_maxImageUnits);
164 qCDebug(Backend) << "context supports" << m_maxImageUnits << "image units";
165
166 if (m_gl->format().majorVersion() >= 3) {
167 m_supportsVAO = true;
168 } else {
169 QSet<QByteArray> extensions = m_gl->extensions();
170 m_supportsVAO = extensions.contains(QByteArrayLiteral("GL_OES_vertex_array_object"))
171 || extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
172 || extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
173 }
174
175 m_defaultFBO = m_gl->defaultFramebufferObject();
176 qCDebug(Backend) << "VAO support = " << m_supportsVAO;
177}
178
179void GraphicsContext::clearBackBuffer(QClearBuffers::BufferTypeFlags buffers)
180{
181 if (buffers != QClearBuffers::None) {
182 GLbitfield mask = 0;
183
184 if (buffers & QClearBuffers::ColorBuffer)
185 mask |= GL_COLOR_BUFFER_BIT;
186 if (buffers & QClearBuffers::DepthBuffer)
187 mask |= GL_DEPTH_BUFFER_BIT;
188 if (buffers & QClearBuffers::StencilBuffer)
189 mask |= GL_STENCIL_BUFFER_BIT;
190
191 m_gl->functions()->glClear(mask);
192 }
193}
194
195bool GraphicsContext::hasValidGLHelper() const
196{
197 return m_glHelper != nullptr;
198}
199
200bool GraphicsContext::isInitialized() const
201{
202 return m_initialized;
203}
204
205bool GraphicsContext::makeCurrent(QSurface *surface)
206{
207 Q_ASSERT(m_gl);
208 if (!m_gl->makeCurrent(surface)) {
209 qCWarning(Backend) << Q_FUNC_INFO << "makeCurrent failed";
210 return false;
211 }
212
213 initializeHelpers(surface);
214
215 return true;
216}
217
218void GraphicsContext::initializeHelpers(QSurface *surface)
219{
220 // Set the correct GL Helper depending on the surface
221 // If no helper exists, create one
222 m_glHelper = m_glHelpers.value(akey: surface);
223 if (!m_glHelper) {
224 m_glHelper = resolveHighestOpenGLFunctions();
225 m_glHelpers.insert(akey: surface, avalue: m_glHelper);
226 }
227}
228
229void GraphicsContext::doneCurrent()
230{
231 Q_ASSERT(m_gl);
232 m_gl->doneCurrent();
233 m_glHelper = nullptr;
234}
235
236// Called by GraphicsContext::loadShader itself called by Renderer::updateGLResources
237GraphicsContext::ShaderCreationInfo GraphicsContext::createShaderProgram(GLShader *shader)
238{
239 QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
240
241 // Compile shaders
242 const auto shaderCode = shader->shaderCode();
243
244 QString logs;
245 for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
246 const QShaderProgram::ShaderType type = static_cast<QShaderProgram::ShaderType>(i);
247 if (!shaderCode.at(i).isEmpty()) {
248 // Note: logs only return the error but not all the shader code
249 // we could append it
250 if (!shaderProgram->addCacheableShaderFromSourceCode(type: shaderType(type), source: shaderCode.at(i)))
251 logs += shaderProgram->log();
252 }
253 }
254
255 // Call glBindFragDataLocation and link the program
256 // Since we are sharing shaders in the backend, we assume that if using custom
257 // fragOutputs, they should all be the same for a given shader
258 bindFragOutputs(shader: shaderProgram->programId(), outputs: shader->fragOutputs());
259
260 const bool linkSucceeded = shaderProgram->link();
261 logs += shaderProgram->log();
262
263 // Perform shader introspection
264 introspectShaderInterface(shader);
265
266 ShaderCreationInfo info;
267 info.linkSucceeded = linkSucceeded;
268 info.logs = logs;
269
270 return info;
271}
272
273// That assumes that the shaderProgram in Shader stays the same
274void GraphicsContext::introspectShaderInterface(GLShader *shader)
275{
276 QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
277 GraphicsHelperInterface *glHelper = resolveHighestOpenGLFunctions();
278 shader->initializeUniforms(uniformsDescription: glHelper->programUniformsAndLocations(programId: shaderProgram->programId()));
279 shader->initializeAttributes(attributesDescription: glHelper->programAttributesAndLocations(programId: shaderProgram->programId()));
280 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::UniformBufferObject))
281 shader->initializeUniformBlocks(uniformBlockDescription: m_glHelper->programUniformBlocks(programId: shaderProgram->programId()));
282 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::ShaderStorageObject))
283 shader->initializeShaderStorageBlocks(shaderStorageBlockDescription: m_glHelper->programShaderStorageBlocks(programId: shaderProgram->programId()));
284}
285
286
287// Called by Renderer::updateGLResources
288void GraphicsContext::loadShader(Shader *shaderNode,
289 ShaderManager *shaderManager,
290 GLShaderManager *glShaderManager)
291{
292 const Qt3DCore::QNodeId shaderId = shaderNode->peerId();
293 GLShader *glShader = glShaderManager->lookupResource(shaderId);
294
295 // We already have a shader associated with the node
296 if (glShader != nullptr) {
297 // We need to abandon it
298 glShaderManager->abandon(apiShader: glShader, shader: shaderNode);
299 }
300
301 // We create or adopt an already created glShader
302 glShader = glShaderManager->createOrAdoptExisting(shader: shaderNode);
303
304 const QVector<Qt3DCore::QNodeId> sharedShaderIds = glShaderManager->shaderIdsForProgram(glShader);
305 if (sharedShaderIds.size() == 1) {
306 // The Shader could already be loaded if we retrieved one
307 // that had been marked for destruction
308 if (!glShader->isLoaded()) {
309 glShader->setGraphicsContext(this);
310 glShader->setShaderCode(shaderNode->shaderCode());
311 const ShaderCreationInfo loadResult = createShaderProgram(shader: glShader);
312 shaderNode->setStatus(loadResult.linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error);
313 shaderNode->setLog(loadResult.logs);
314 // Loaded in the sense we tried to load it (and maybe it failed)
315 glShader->setLoaded(true);
316 }
317 } else {
318 // Find an already loaded shader that shares the same QOpenGLShaderProgram
319 for (const Qt3DCore::QNodeId sharedShaderId : sharedShaderIds) {
320 if (sharedShaderId != shaderNode->peerId()) {
321 Shader *refShader = shaderManager->lookupResource(id: sharedShaderId);
322 // We only introspect once per actual OpenGL shader program
323 // rather than once per ShaderNode.
324 shaderNode->initializeFromReference(other: *refShader);
325 break;
326 }
327 }
328 }
329 shaderNode->unsetDirty();
330 // Ensure we will rebuilt material caches
331 shaderNode->requestCacheRebuild();
332}
333
334void GraphicsContext::activateDrawBuffers(const AttachmentPack &attachments)
335{
336 const QVector<int> activeDrawBuffers = attachments.getGlDrawBuffers();
337
338 if (m_glHelper->checkFrameBufferComplete()) {
339 if (activeDrawBuffers.size() > 1) {// We need MRT
340 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT)) {
341 // Set up MRT, glDrawBuffers...
342 m_glHelper->drawBuffers(n: activeDrawBuffers.size(), bufs: activeDrawBuffers.data());
343 }
344 }
345 } else {
346 qWarning() << "FBO incomplete";
347 }
348}
349
350void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode)
351{
352 m_glHelper->rasterMode(faceMode, rasterMode);
353}
354
355/*!
356 * \internal
357 * Finds the highest supported opengl version and internally use the most optimized
358 * helper for a given version.
359 */
360GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
361{
362 Q_ASSERT(m_gl);
363 GraphicsHelperInterface *glHelper = nullptr;
364
365 if (m_gl->isOpenGLES()) {
366 if (m_gl->format().majorVersion() >= 3) {
367 if (m_gl->format().minorVersion() >= 2) {
368 glHelper = new GraphicsHelperES3_2;
369 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper";
370 } else if (m_gl->format().minorVersion() >= 1) {
371 glHelper = new GraphicsHelperES3_1;
372 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.1 Helper";
373 } else {
374 glHelper = new GraphicsHelperES3();
375 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper";
376 }
377 } else {
378 glHelper = new GraphicsHelperES2();
379 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper";
380 }
381 glHelper->initializeHelper(context: m_gl, functions: nullptr);
382 }
383#ifndef QT_OPENGL_ES_2
384 else {
385 QAbstractOpenGLFunctions *glFunctions = nullptr;
386 if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_4_3_Core>()) != nullptr) {
387 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 4.3";
388 glHelper = new GraphicsHelperGL4();
389 } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_3_Core>()) != nullptr) {
390 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.3";
391 glHelper = new GraphicsHelperGL3_3();
392 } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) {
393 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2";
394 glHelper = new GraphicsHelperGL3_2();
395 } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) {
396 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper";
397 glHelper = new GraphicsHelperGL2();
398 }
399 Q_ASSERT_X(glHelper, "GraphicsContext::resolveHighestOpenGLFunctions", "unable to create valid helper for available OpenGL version");
400 glHelper->initializeHelper(context: m_gl, functions: glFunctions);
401 }
402#endif
403
404 // Note: at this point we are certain the context (m_gl) is current with a surface
405 const QByteArray debugLoggingMode = qgetenv(varName: "QT3DRENDER_DEBUG_LOGGING");
406 const bool enableDebugLogging = !debugLoggingMode.isEmpty();
407
408 if (enableDebugLogging && !m_debugLogger) {
409 if (m_gl->hasExtension(extension: "GL_KHR_debug")) {
410 qCDebug(Backend) << "Qt3D: Enabling OpenGL debug logging";
411 m_debugLogger.reset(other: new QOpenGLDebugLogger);
412 if (m_debugLogger->initialize()) {
413 QObject::connect(sender: m_debugLogger.data(), signal: &QOpenGLDebugLogger::messageLogged, slot: &logOpenGLDebugMessage);
414 const QString mode = QString::fromLocal8Bit(str: debugLoggingMode);
415 m_debugLogger->startLogging(loggingMode: mode.startsWith(s: QLatin1String("sync"), cs: Qt::CaseInsensitive)
416 ? QOpenGLDebugLogger::SynchronousLogging
417 : QOpenGLDebugLogger::AsynchronousLogging);
418
419 const auto msgs = m_debugLogger->loggedMessages();
420 for (const QOpenGLDebugMessage &msg : msgs)
421 logOpenGLDebugMessage(debugMessage: msg);
422 }
423 } else {
424 qCDebug(Backend) << "Qt3D: OpenGL debug logging requested but GL_KHR_debug not supported";
425 }
426 }
427
428
429 // Set Vendor and Extensions of reference GraphicsApiFilter
430 // TO DO: would that vary like the glHelper ?
431
432 QStringList extensions;
433 const auto exts = m_gl->extensions();
434 for (const QByteArray &ext : exts)
435 extensions << QString::fromUtf8(str: ext);
436 m_contextInfo.m_major = m_gl->format().version().first;
437 m_contextInfo.m_minor = m_gl->format().version().second;
438 m_contextInfo.m_api = m_gl->isOpenGLES() ? QGraphicsApiFilter::OpenGLES : QGraphicsApiFilter::OpenGL;
439 m_contextInfo.m_profile = static_cast<QGraphicsApiFilter::OpenGLProfile>(m_gl->format().profile());
440 m_contextInfo.m_extensions = extensions;
441 m_contextInfo.m_vendor = QString::fromUtf8(str: reinterpret_cast<const char *>(m_gl->functions()->glGetString(GL_VENDOR)));
442
443 return glHelper;
444}
445
446const GraphicsApiFilterData *GraphicsContext::contextInfo() const
447{
448 return &m_contextInfo;
449}
450
451bool GraphicsContext::supportsDrawBuffersBlend() const
452{
453 return m_glHelper->supportsFeature(feature: GraphicsHelperInterface::DrawBuffersBlend);
454}
455
456/*!
457 * \internal
458 * Wraps an OpenGL call to glDrawElementsInstanced.
459 * If the call is not supported by the system's OpenGL version,
460 * it is simulated with a loop.
461 */
462void GraphicsContext::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
463 GLsizei primitiveCount,
464 GLint indexType,
465 void *indices,
466 GLsizei instances,
467 GLint baseVertex,
468 GLint baseInstance)
469{
470 m_glHelper->drawElementsInstancedBaseVertexBaseInstance(primitiveType,
471 primitiveCount,
472 indexType,
473 indices,
474 instances,
475 baseVertex,
476 baseInstance);
477}
478
479/*!
480 * \internal
481 * Wraps an OpenGL call to glDrawArraysInstanced.
482 */
483void GraphicsContext::drawArraysInstanced(GLenum primitiveType,
484 GLint first,
485 GLsizei count,
486 GLsizei instances)
487{
488 m_glHelper->drawArraysInstanced(primitiveType,
489 first,
490 count,
491 instances);
492}
493
494void GraphicsContext::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance)
495{
496 m_glHelper->drawArraysInstancedBaseInstance(primitiveType,
497 first,
498 count,
499 instances,
500 baseinstance);
501}
502
503/*!
504 * \internal
505 * Wraps an OpenGL call to glDrawElements.
506 */
507void GraphicsContext::drawElements(GLenum primitiveType,
508 GLsizei primitiveCount,
509 GLint indexType,
510 void *indices,
511 GLint baseVertex)
512{
513 m_glHelper->drawElements(primitiveType,
514 primitiveCount,
515 indexType,
516 indices,
517 baseVertex);
518}
519
520void GraphicsContext::drawElementsIndirect(GLenum mode,
521 GLenum type,
522 void *indirect)
523{
524 m_glHelper->drawElementsIndirect(mode, type, indirect);
525}
526
527/*!
528 * \internal
529 * Wraps an OpenGL call to glDrawArrays.
530 */
531void GraphicsContext::drawArrays(GLenum primitiveType,
532 GLint first,
533 GLsizei count)
534{
535 m_glHelper->drawArrays(primitiveType,
536 first,
537 count);
538}
539
540void GraphicsContext::drawArraysIndirect(GLenum mode, void *indirect)
541{
542 m_glHelper->drawArraysIndirect(mode, indirect);
543}
544
545void GraphicsContext::setVerticesPerPatch(GLint verticesPerPatch)
546{
547 m_glHelper->setVerticesPerPatch(verticesPerPatch);
548}
549
550void GraphicsContext::blendEquation(GLenum mode)
551{
552 m_glHelper->blendEquation(mode);
553}
554
555void GraphicsContext::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
556{
557 m_glHelper->blendFunci(buf, sfactor, dfactor);
558}
559
560void GraphicsContext::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
561{
562 m_glHelper->blendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha);
563}
564
565void GraphicsContext::alphaTest(GLenum mode1, GLenum mode2)
566{
567 m_glHelper->alphaTest(mode1, mode2);
568}
569
570void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode)
571{
572 m_glHelper->bindFrameBufferObject(frameBufferId: fbo, mode);
573}
574
575void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue)
576{
577 m_glHelper->depthRange(nearValue, farValue);
578}
579
580void GraphicsContext::depthTest(GLenum mode)
581{
582 m_glHelper->depthTest(mode);
583}
584
585void GraphicsContext::depthMask(GLenum mode)
586{
587 m_glHelper->depthMask(mode);
588}
589
590void GraphicsContext::frontFace(GLenum mode)
591{
592 m_glHelper->frontFace(mode);
593}
594
595void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs)
596{
597 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT) &&
598 m_glHelper->supportsFeature(feature: GraphicsHelperInterface::BindableFragmentOutputs))
599 m_glHelper->bindFragDataLocation(shader, outputs);
600}
601
602void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture,
603 GLint mipLevel, GLboolean layered,
604 GLint layer, GLenum access, GLenum format)
605{
606 m_glHelper->bindImageTexture(imageUnit,
607 texture,
608 mipLevel,
609 layered,
610 layer,
611 access,
612 format);
613}
614
615void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
616{
617 m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding);
618}
619
620void GraphicsContext::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
621{
622 m_glHelper->bindShaderStorageBlock(programId, shaderStorageBlockIndex, shaderStorageBlockBinding);
623}
624
625void GraphicsContext::bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer)
626{
627 m_glHelper->bindBufferBase(target, index: bindingIndex, buffer);
628}
629
630void GraphicsContext::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
631{
632 m_glHelper->buildUniformBuffer(v, description, buffer);
633}
634
635void GraphicsContext::setMSAAEnabled(bool enabled)
636{
637 m_glHelper->setMSAAEnabled(enabled);
638}
639
640void GraphicsContext::setAlphaCoverageEnabled(bool enabled)
641{
642 m_glHelper->setAlphaCoverageEnabled(enabled);
643}
644
645void GraphicsContext::clearBufferf(GLint drawbuffer, const QVector4D &values)
646{
647 m_glHelper->clearBufferf(drawbuffer, values);
648}
649
650GLuint GraphicsContext::boundFrameBufferObject()
651{
652 return m_glHelper->boundFrameBufferObject();
653}
654
655void GraphicsContext::clearColor(const QColor &color)
656{
657 m_gl->functions()->glClearColor(red: color.redF(), green: color.greenF(), blue: color.blueF(), alpha: color.alphaF());
658}
659
660void GraphicsContext::clearDepthValue(float depth)
661{
662 m_gl->functions()->glClearDepthf(depth);
663}
664
665void GraphicsContext::clearStencilValue(int stencil)
666{
667 m_gl->functions()->glClearStencil(s: stencil);
668}
669
670void GraphicsContext::enableClipPlane(int clipPlane)
671{
672 m_glHelper->enableClipPlane(clipPlane);
673}
674
675void GraphicsContext::disableClipPlane(int clipPlane)
676{
677 m_glHelper->disableClipPlane(clipPlane);
678}
679
680void GraphicsContext::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
681{
682 m_glHelper->setClipPlane(clipPlane, normal, distance);
683}
684
685GLint GraphicsContext::maxClipPlaneCount()
686{
687 return m_glHelper->maxClipPlaneCount();
688}
689
690GLint GraphicsContext::maxTextureUnitsCount() const
691{
692 return m_maxTextureUnits;
693}
694
695GLint GraphicsContext::maxImageUnitsCount() const
696{
697 return m_maxImageUnits;
698}
699
700
701void GraphicsContext::enablePrimitiveRestart(int restartIndex)
702{
703 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart))
704 m_glHelper->enablePrimitiveRestart(primitiveRestartIndex: restartIndex);
705}
706
707void GraphicsContext::disablePrimitiveRestart()
708{
709 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart))
710 m_glHelper->disablePrimitiveRestart();
711}
712
713void GraphicsContext::pointSize(bool programmable, GLfloat value)
714{
715 m_glHelper->pointSize(programmable, value);
716}
717
718void GraphicsContext::dispatchCompute(int x, int y, int z)
719{
720 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::Compute))
721 m_glHelper->dispatchCompute(wx: x, wy: y, wz: z);
722}
723
724GLboolean GraphicsContext::unmapBuffer(GLenum target)
725{
726 return m_glHelper->unmapBuffer(target);
727}
728
729char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size)
730{
731 return m_glHelper->mapBuffer(target, size);
732}
733
734void GraphicsContext::enablei(GLenum cap, GLuint index)
735{
736 m_glHelper->enablei(cap, index);
737}
738
739void GraphicsContext::disablei(GLenum cap, GLuint index)
740{
741 m_glHelper->disablei(cap, index);
742}
743
744void GraphicsContext::setSeamlessCubemap(bool enable)
745{
746 m_glHelper->setSeamlessCubemap(enable);
747}
748
749void GraphicsContext::readBuffer(GLenum mode)
750{
751 m_glHelper->readBuffer(mode);
752}
753
754void GraphicsContext::drawBuffer(GLenum mode)
755{
756 m_glHelper->drawBuffer(mode);
757}
758
759void GraphicsContext::drawBuffers(GLsizei n, const int *bufs)
760{
761 m_glHelper->drawBuffers(n, bufs);
762}
763
764void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v)
765{
766 const UniformType type = m_glHelper->uniformTypeFromGLType(glType: description.m_type);
767
768 switch (type) {
769 case UniformType::Float:
770 // See QTBUG-57510 and uniform_p.h
771 if (v.storedType() == Int) {
772 float value = float(*v.constData<int>());
773 UniformValue floatV(value);
774 applyUniformHelper<UniformType::Float>(description, value: floatV);
775 } else {
776 applyUniformHelper<UniformType::Float>(description, value: v);
777 }
778 break;
779 case UniformType::Vec2:
780 applyUniformHelper<UniformType::Vec2>(description, value: v);
781 break;
782 case UniformType::Vec3:
783 applyUniformHelper<UniformType::Vec3>(description, value: v);
784 break;
785 case UniformType::Vec4:
786 applyUniformHelper<UniformType::Vec4>(description, value: v);
787 break;
788
789 case UniformType::Double:
790 applyUniformHelper<UniformType::Double>(description, v);
791 break;
792 case UniformType::DVec2:
793 applyUniformHelper<UniformType::DVec2>(description, v);
794 break;
795 case UniformType::DVec3:
796 applyUniformHelper<UniformType::DVec3>(description, v);
797 break;
798 case UniformType::DVec4:
799 applyUniformHelper<UniformType::DVec4>(description, v);
800 break;
801
802 case UniformType::Sampler:
803 case UniformType::Image:
804 case UniformType::Int:
805 applyUniformHelper<UniformType::Int>(description, value: v);
806 break;
807 case UniformType::IVec2:
808 applyUniformHelper<UniformType::IVec2>(description, value: v);
809 break;
810 case UniformType::IVec3:
811 applyUniformHelper<UniformType::IVec3>(description, value: v);
812 break;
813 case UniformType::IVec4:
814 applyUniformHelper<UniformType::IVec4>(description, value: v);
815 break;
816
817 case UniformType::UInt:
818 applyUniformHelper<UniformType::UInt>(description, value: v);
819 break;
820 case UniformType::UIVec2:
821 applyUniformHelper<UniformType::UIVec2>(description, value: v);
822 break;
823 case UniformType::UIVec3:
824 applyUniformHelper<UniformType::UIVec3>(description, value: v);
825 break;
826 case UniformType::UIVec4:
827 applyUniformHelper<UniformType::UIVec4>(description, value: v);
828 break;
829
830 case UniformType::Bool:
831 applyUniformHelper<UniformType::Bool>(description, value: v);
832 break;
833 case UniformType::BVec2:
834 applyUniformHelper<UniformType::BVec2>(description, value: v);
835 break;
836 case UniformType::BVec3:
837 applyUniformHelper<UniformType::BVec3>(description, value: v);
838 break;
839 case UniformType::BVec4:
840 applyUniformHelper<UniformType::BVec4>(description, value: v);
841 break;
842
843 case UniformType::Mat2:
844 applyUniformHelper<UniformType::Mat2>(description, value: v);
845 break;
846 case UniformType::Mat3:
847 applyUniformHelper<UniformType::Mat3>(description, value: v);
848 break;
849 case UniformType::Mat4:
850 applyUniformHelper<UniformType::Mat4>(description, value: v);
851 break;
852 case UniformType::Mat2x3:
853 applyUniformHelper<UniformType::Mat2x3>(description, value: v);
854 break;
855 case UniformType::Mat3x2:
856 applyUniformHelper<UniformType::Mat3x2>(description, value: v);
857 break;
858 case UniformType::Mat2x4:
859 applyUniformHelper<UniformType::Mat2x4>(description, value: v);
860 break;
861 case UniformType::Mat4x2:
862 applyUniformHelper<UniformType::Mat4x2>(description, value: v);
863 break;
864 case UniformType::Mat3x4:
865 applyUniformHelper<UniformType::Mat3x4>(description, value: v);
866 break;
867 case UniformType::Mat4x3:
868 applyUniformHelper<UniformType::Mat4x3>(description, value: v);
869 break;
870
871 default:
872 break;
873 }
874}
875
876void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
877{
878 m_glHelper->memoryBarrier(barriers);
879}
880
881GLint GraphicsContext::elementType(GLint type)
882{
883 switch (type) {
884 case GL_FLOAT:
885 case GL_FLOAT_VEC2:
886 case GL_FLOAT_VEC3:
887 case GL_FLOAT_VEC4:
888 return GL_FLOAT;
889
890#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
891 case GL_DOUBLE:
892#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems
893 case GL_DOUBLE_VEC2:
894 case GL_DOUBLE_VEC3:
895 case GL_DOUBLE_VEC4:
896#endif
897 return GL_DOUBLE;
898#endif
899 default:
900 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
901 }
902
903 return GL_INVALID_VALUE;
904}
905
906GLint GraphicsContext::tupleSizeFromType(GLint type)
907{
908 switch (type) {
909 case GL_FLOAT:
910#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
911 case GL_DOUBLE:
912#endif
913 case GL_UNSIGNED_BYTE:
914 case GL_UNSIGNED_INT:
915 break; // fall through
916
917 case GL_FLOAT_VEC2:
918#ifdef GL_DOUBLE_VEC2 // For compiling on pre GL 4.1 systems.
919 case GL_DOUBLE_VEC2:
920#endif
921 return 2;
922
923 case GL_FLOAT_VEC3:
924#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems.
925 case GL_DOUBLE_VEC3:
926#endif
927 return 3;
928
929 case GL_FLOAT_VEC4:
930#ifdef GL_DOUBLE_VEC4 // For compiling on pre GL 4.1 systems.
931 case GL_DOUBLE_VEC4:
932#endif
933 return 4;
934
935 default:
936 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
937 }
938
939 return 1;
940}
941
942GLuint GraphicsContext::byteSizeFromType(GLint type)
943{
944 switch (type) {
945 case GL_FLOAT: return sizeof(float);
946#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
947 case GL_DOUBLE: return sizeof(double);
948#endif
949 case GL_UNSIGNED_BYTE: return sizeof(unsigned char);
950 case GL_UNSIGNED_INT: return sizeof(GLuint);
951
952 case GL_FLOAT_VEC2: return sizeof(float) * 2;
953 case GL_FLOAT_VEC3: return sizeof(float) * 3;
954 case GL_FLOAT_VEC4: return sizeof(float) * 4;
955#ifdef GL_DOUBLE_VEC3 // Required to compile on pre GL 4.1 systems
956 case GL_DOUBLE_VEC2: return sizeof(double) * 2;
957 case GL_DOUBLE_VEC3: return sizeof(double) * 3;
958 case GL_DOUBLE_VEC4: return sizeof(double) * 4;
959#endif
960 default:
961 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
962 }
963
964 return 0;
965}
966
967GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseType dataType)
968{
969 switch (dataType) {
970 case QAttribute::Byte:
971 return GL_BYTE;
972 case QAttribute::UnsignedByte:
973 return GL_UNSIGNED_BYTE;
974 case QAttribute::Short:
975 return GL_SHORT;
976 case QAttribute::UnsignedShort:
977 return GL_UNSIGNED_SHORT;
978 case QAttribute::Int:
979 return GL_INT;
980 case QAttribute::UnsignedInt:
981 return GL_UNSIGNED_INT;
982 case QAttribute::HalfFloat:
983#ifdef GL_HALF_FLOAT
984 return GL_HALF_FLOAT;
985#endif
986#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
987 case QAttribute::Double:
988 return GL_DOUBLE;
989#endif
990 case QAttribute::Float:
991 break;
992 default:
993 qWarning() << Q_FUNC_INFO << "unsupported dataType:" << dataType;
994 }
995 return GL_FLOAT;
996}
997
998QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
999QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv)
1000QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv)
1001QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv)
1002
1003// OpenGL expects int* as values for booleans
1004QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv)
1005QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv)
1006QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv)
1007QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv)
1008
1009QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv)
1010QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv)
1011QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv)
1012QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv)
1013
1014QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv)
1015QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv)
1016QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv)
1017QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv)
1018
1019QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv)
1020QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv)
1021QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv)
1022QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv)
1023QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv)
1024QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv)
1025QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv)
1026QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv)
1027QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv)
1028
1029} // namespace OpenGL
1030} // namespace Render
1031} // namespace Qt3DRender of namespace
1032
1033QT_END_NAMESPACE
1034

source code of qt3d/src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp