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

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