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::activateDrawBuffers(const AttachmentPack &attachments)
304{
305 const std::vector<int> &activeDrawBuffers = attachments.getGlDrawBuffers();
306
307 if (m_glHelper->checkFrameBufferComplete()) {
308 if (activeDrawBuffers.size() > 1) {// We need MRT
309 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT)) {
310 // Set up MRT, glDrawBuffers...
311 m_glHelper->drawBuffers(n: GLsizei(activeDrawBuffers.size()), bufs: activeDrawBuffers.data());
312 }
313 }
314 } else {
315 qWarning() << "FBO incomplete";
316 }
317}
318
319void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode)
320{
321 m_glHelper->rasterMode(faceMode, rasterMode);
322}
323
324/*!
325 * \internal
326 * Finds the highest supported opengl version and internally use the most optimized
327 * helper for a given version.
328 */
329GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
330{
331 Q_ASSERT(m_gl);
332 GraphicsHelperInterface *glHelper = nullptr;
333
334 if (m_gl->isOpenGLES()) {
335 if (m_gl->format().majorVersion() >= 3) {
336 if (m_gl->format().minorVersion() >= 2) {
337 glHelper = new GraphicsHelperES3_2;
338 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper";
339 } else if (m_gl->format().minorVersion() >= 1) {
340 glHelper = new GraphicsHelperES3_1;
341 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.1 Helper";
342 } else {
343 glHelper = new GraphicsHelperES3();
344 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper";
345 }
346 } else {
347 glHelper = new GraphicsHelperES2();
348 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper";
349 }
350 glHelper->initializeHelper(context: m_gl, functions: nullptr);
351 }
352#if !QT_CONFIG(opengles2)
353 else {
354 QAbstractOpenGLFunctions *glFunctions = nullptr;
355 if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_4_3_Core>()) != nullptr) {
356 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 4.3";
357 glHelper = new GraphicsHelperGL4();
358 } else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_3_3_Core>()) != nullptr) {
359 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.3";
360 glHelper = new GraphicsHelperGL3_3();
361 } else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_3_2_Core>()) != nullptr) {
362 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2";
363 glHelper = new GraphicsHelperGL3_2();
364 } else if ((glFunctions = QOpenGLVersionFunctionsFactory::get<QOpenGLFunctions_2_0>()) != nullptr) {
365 qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper";
366 glHelper = new GraphicsHelperGL2();
367 }
368 Q_ASSERT_X(glHelper, "GraphicsContext::resolveHighestOpenGLFunctions", "unable to create valid helper for available OpenGL version");
369 glHelper->initializeHelper(context: m_gl, functions: glFunctions);
370 }
371#endif
372
373 // Note: at this point we are certain the context (m_gl) is current with a surface
374 const QByteArray debugLoggingMode = qgetenv(varName: "QT3DRENDER_DEBUG_LOGGING");
375 const bool enableDebugLogging = !debugLoggingMode.isEmpty();
376
377#ifdef QT_OPENGL_LIB
378 if (enableDebugLogging && !m_debugLogger) {
379 if (m_gl->hasExtension(extension: "GL_KHR_debug")) {
380 qCDebug(Backend) << "Qt3D: Enabling OpenGL debug logging";
381 m_debugLogger.reset(other: new QOpenGLDebugLogger);
382 if (m_debugLogger->initialize()) {
383 QObject::connect(sender: m_debugLogger.data(), signal: &QOpenGLDebugLogger::messageLogged, slot: &logOpenGLDebugMessage);
384 const QString mode = QString::fromLocal8Bit(ba: debugLoggingMode);
385 m_debugLogger->startLogging(loggingMode: mode.startsWith(s: QLatin1String("sync"), cs: Qt::CaseInsensitive)
386 ? QOpenGLDebugLogger::SynchronousLogging
387 : QOpenGLDebugLogger::AsynchronousLogging);
388
389 const auto msgs = m_debugLogger->loggedMessages();
390 for (const QOpenGLDebugMessage &msg : msgs)
391 logOpenGLDebugMessage(debugMessage: msg);
392 }
393 } else {
394 qCDebug(Backend) << "Qt3D: OpenGL debug logging requested but GL_KHR_debug not supported";
395 }
396 }
397#endif
398
399 // Set Vendor and Extensions of reference GraphicsApiFilter
400 // TO DO: would that vary like the glHelper ?
401
402 QStringList extensions;
403 const auto exts = m_gl->extensions();
404 for (const QByteArray &ext : exts)
405 extensions << QString::fromUtf8(ba: ext);
406 m_contextInfo.m_major = m_gl->format().version().first;
407 m_contextInfo.m_minor = m_gl->format().version().second;
408 m_contextInfo.m_api = m_gl->isOpenGLES() ? QGraphicsApiFilter::OpenGLES : QGraphicsApiFilter::OpenGL;
409 m_contextInfo.m_profile = static_cast<QGraphicsApiFilter::OpenGLProfile>(m_gl->format().profile());
410 m_contextInfo.m_extensions = extensions;
411 m_contextInfo.m_vendor = QString::fromUtf8(utf8: reinterpret_cast<const char *>(m_gl->functions()->glGetString(GL_VENDOR)));
412
413 return glHelper;
414}
415
416const GraphicsApiFilterData *GraphicsContext::contextInfo() const
417{
418 return &m_contextInfo;
419}
420
421bool GraphicsContext::supportsDrawBuffersBlend() const
422{
423 return m_glHelper->supportsFeature(feature: GraphicsHelperInterface::DrawBuffersBlend);
424}
425
426/*!
427 * \internal
428 * Wraps an OpenGL call to glDrawElementsInstanced.
429 * If the call is not supported by the system's OpenGL version,
430 * it is simulated with a loop.
431 */
432void GraphicsContext::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
433 GLsizei primitiveCount,
434 GLint indexType,
435 void *indices,
436 GLsizei instances,
437 GLint baseVertex,
438 GLint baseInstance)
439{
440 m_glHelper->drawElementsInstancedBaseVertexBaseInstance(primitiveType,
441 primitiveCount,
442 indexType,
443 indices,
444 instances,
445 baseVertex,
446 baseInstance);
447}
448
449/*!
450 * \internal
451 * Wraps an OpenGL call to glDrawArraysInstanced.
452 */
453void GraphicsContext::drawArraysInstanced(GLenum primitiveType,
454 GLint first,
455 GLsizei count,
456 GLsizei instances)
457{
458 m_glHelper->drawArraysInstanced(primitiveType,
459 first,
460 count,
461 instances);
462}
463
464void GraphicsContext::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance)
465{
466 m_glHelper->drawArraysInstancedBaseInstance(primitiveType,
467 first,
468 count,
469 instances,
470 baseinstance);
471}
472
473/*!
474 * \internal
475 * Wraps an OpenGL call to glDrawElements.
476 */
477void GraphicsContext::drawElements(GLenum primitiveType,
478 GLsizei primitiveCount,
479 GLint indexType,
480 void *indices,
481 GLint baseVertex)
482{
483 m_glHelper->drawElements(primitiveType,
484 primitiveCount,
485 indexType,
486 indices,
487 baseVertex);
488}
489
490void GraphicsContext::drawElementsIndirect(GLenum mode,
491 GLenum type,
492 void *indirect)
493{
494 m_glHelper->drawElementsIndirect(mode, type, indirect);
495}
496
497/*!
498 * \internal
499 * Wraps an OpenGL call to glDrawArrays.
500 */
501void GraphicsContext::drawArrays(GLenum primitiveType,
502 GLint first,
503 GLsizei count)
504{
505 m_glHelper->drawArrays(primitiveType,
506 first,
507 count);
508}
509
510void GraphicsContext::drawArraysIndirect(GLenum mode, void *indirect)
511{
512 m_glHelper->drawArraysIndirect(mode, indirect);
513}
514
515void GraphicsContext::setVerticesPerPatch(GLint verticesPerPatch)
516{
517 m_glHelper->setVerticesPerPatch(verticesPerPatch);
518}
519
520void GraphicsContext::blendEquation(GLenum mode)
521{
522 m_glHelper->blendEquation(mode);
523}
524
525void GraphicsContext::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
526{
527 m_glHelper->blendFunci(buf, sfactor, dfactor);
528}
529
530void GraphicsContext::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
531{
532 m_glHelper->blendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha);
533}
534
535void GraphicsContext::alphaTest(GLenum mode1, GLenum mode2)
536{
537 m_glHelper->alphaTest(mode1, mode2);
538}
539
540void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode)
541{
542 m_glHelper->bindFrameBufferObject(frameBufferId: fbo, mode);
543}
544
545void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue)
546{
547 m_glHelper->depthRange(nearValue, farValue);
548}
549
550void GraphicsContext::depthTest(GLenum mode)
551{
552 m_glHelper->depthTest(mode);
553}
554
555void GraphicsContext::depthMask(GLenum mode)
556{
557 m_glHelper->depthMask(mode);
558}
559
560void GraphicsContext::frontFace(GLenum mode)
561{
562 m_glHelper->frontFace(mode);
563}
564
565void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs)
566{
567 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::MRT) &&
568 m_glHelper->supportsFeature(feature: GraphicsHelperInterface::BindableFragmentOutputs))
569 m_glHelper->bindFragDataLocation(shader, outputs);
570}
571
572void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture,
573 GLint mipLevel, GLboolean layered,
574 GLint layer, GLenum access, GLenum format)
575{
576 m_glHelper->bindImageTexture(imageUnit,
577 texture,
578 mipLevel,
579 layered,
580 layer,
581 access,
582 format);
583}
584
585void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
586{
587 m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding);
588}
589
590void GraphicsContext::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
591{
592 m_glHelper->bindShaderStorageBlock(programId, shaderStorageBlockIndex, shaderStorageBlockBinding);
593}
594
595void GraphicsContext::bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer)
596{
597 m_glHelper->bindBufferBase(target, index: bindingIndex, buffer);
598}
599
600void GraphicsContext::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
601{
602 m_glHelper->buildUniformBuffer(v, description, buffer);
603}
604
605void GraphicsContext::setMSAAEnabled(bool enabled)
606{
607 m_glHelper->setMSAAEnabled(enabled);
608}
609
610void GraphicsContext::setAlphaCoverageEnabled(bool enabled)
611{
612 m_glHelper->setAlphaCoverageEnabled(enabled);
613}
614
615void GraphicsContext::clearBufferf(GLint drawbuffer, const QVector4D &values)
616{
617 m_glHelper->clearBufferf(drawbuffer, values);
618}
619
620GLuint GraphicsContext::boundFrameBufferObject()
621{
622 return m_glHelper->boundFrameBufferObject();
623}
624
625void GraphicsContext::clearColor(const QColor &color)
626{
627 m_gl->functions()->glClearColor(red: color.redF(), green: color.greenF(), blue: color.blueF(), alpha: color.alphaF());
628}
629
630void GraphicsContext::clearDepthValue(float depth)
631{
632 m_gl->functions()->glClearDepthf(depth);
633}
634
635void GraphicsContext::clearStencilValue(int stencil)
636{
637 m_gl->functions()->glClearStencil(s: stencil);
638}
639
640void GraphicsContext::enableClipPlane(int clipPlane)
641{
642 m_glHelper->enableClipPlane(clipPlane);
643}
644
645void GraphicsContext::disableClipPlane(int clipPlane)
646{
647 m_glHelper->disableClipPlane(clipPlane);
648}
649
650void GraphicsContext::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
651{
652 m_glHelper->setClipPlane(clipPlane, normal, distance);
653}
654
655GLint GraphicsContext::maxClipPlaneCount()
656{
657 return m_glHelper->maxClipPlaneCount();
658}
659
660GLint GraphicsContext::maxTextureUnitsCount() const
661{
662 return m_maxTextureUnits;
663}
664
665GLint GraphicsContext::maxImageUnitsCount() const
666{
667 return m_maxImageUnits;
668}
669
670
671void GraphicsContext::enablePrimitiveRestart(int restartIndex)
672{
673 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart))
674 m_glHelper->enablePrimitiveRestart(primitiveRestartIndex: restartIndex);
675}
676
677void GraphicsContext::disablePrimitiveRestart()
678{
679 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::PrimitiveRestart))
680 m_glHelper->disablePrimitiveRestart();
681}
682
683void GraphicsContext::pointSize(bool programmable, GLfloat value)
684{
685 m_glHelper->pointSize(programmable, value);
686}
687
688void GraphicsContext::dispatchCompute(int x, int y, int z)
689{
690 if (m_glHelper->supportsFeature(feature: GraphicsHelperInterface::Compute))
691 m_glHelper->dispatchCompute(wx: x, wy: y, wz: z);
692}
693
694GLboolean GraphicsContext::unmapBuffer(GLenum target)
695{
696 return m_glHelper->unmapBuffer(target);
697}
698
699char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size)
700{
701 return m_glHelper->mapBuffer(target, size);
702}
703
704void GraphicsContext::enablei(GLenum cap, GLuint index)
705{
706 m_glHelper->enablei(cap, index);
707}
708
709void GraphicsContext::disablei(GLenum cap, GLuint index)
710{
711 m_glHelper->disablei(cap, index);
712}
713
714void GraphicsContext::setSeamlessCubemap(bool enable)
715{
716 m_glHelper->setSeamlessCubemap(enable);
717}
718
719void GraphicsContext::readBuffer(GLenum mode)
720{
721 m_glHelper->readBuffer(mode);
722}
723
724void GraphicsContext::drawBuffer(GLenum mode)
725{
726 m_glHelper->drawBuffer(mode);
727}
728
729void GraphicsContext::drawBuffers(GLsizei n, const int *bufs)
730{
731 m_glHelper->drawBuffers(n, bufs);
732}
733
734void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v)
735{
736 const UniformType type = m_glHelper->uniformTypeFromGLType(glType: description.m_type);
737
738 switch (type) {
739 case UniformType::Float:
740 // See QTBUG-57510 and uniform_p.h
741 if (v.storedType() == Int) {
742 float value = float(*v.constData<int>());
743 UniformValue floatV(value);
744 applyUniformHelper<UniformType::Float>(description, value: floatV);
745 } else {
746 applyUniformHelper<UniformType::Float>(description, value: v);
747 }
748 break;
749 case UniformType::Vec2:
750 applyUniformHelper<UniformType::Vec2>(description, value: v);
751 break;
752 case UniformType::Vec3:
753 applyUniformHelper<UniformType::Vec3>(description, value: v);
754 break;
755 case UniformType::Vec4:
756 applyUniformHelper<UniformType::Vec4>(description, value: v);
757 break;
758
759 case UniformType::Double:
760 applyUniformHelper<UniformType::Double>(description, v);
761 break;
762 case UniformType::DVec2:
763 applyUniformHelper<UniformType::DVec2>(description, v);
764 break;
765 case UniformType::DVec3:
766 applyUniformHelper<UniformType::DVec3>(description, v);
767 break;
768 case UniformType::DVec4:
769 applyUniformHelper<UniformType::DVec4>(description, v);
770 break;
771
772 case UniformType::Sampler:
773 case UniformType::Image:
774 case UniformType::Int:
775 applyUniformHelper<UniformType::Int>(description, value: v);
776 break;
777 case UniformType::IVec2:
778 applyUniformHelper<UniformType::IVec2>(description, value: v);
779 break;
780 case UniformType::IVec3:
781 applyUniformHelper<UniformType::IVec3>(description, value: v);
782 break;
783 case UniformType::IVec4:
784 applyUniformHelper<UniformType::IVec4>(description, value: v);
785 break;
786
787 case UniformType::UInt:
788 applyUniformHelper<UniformType::UInt>(description, value: v);
789 break;
790 case UniformType::UIVec2:
791 applyUniformHelper<UniformType::UIVec2>(description, value: v);
792 break;
793 case UniformType::UIVec3:
794 applyUniformHelper<UniformType::UIVec3>(description, value: v);
795 break;
796 case UniformType::UIVec4:
797 applyUniformHelper<UniformType::UIVec4>(description, value: v);
798 break;
799
800 case UniformType::Bool:
801 applyUniformHelper<UniformType::Bool>(description, value: v);
802 break;
803 case UniformType::BVec2:
804 applyUniformHelper<UniformType::BVec2>(description, value: v);
805 break;
806 case UniformType::BVec3:
807 applyUniformHelper<UniformType::BVec3>(description, value: v);
808 break;
809 case UniformType::BVec4:
810 applyUniformHelper<UniformType::BVec4>(description, value: v);
811 break;
812
813 case UniformType::Mat2:
814 applyUniformHelper<UniformType::Mat2>(description, value: v);
815 break;
816 case UniformType::Mat3:
817 applyUniformHelper<UniformType::Mat3>(description, value: v);
818 break;
819 case UniformType::Mat4:
820 applyUniformHelper<UniformType::Mat4>(description, value: v);
821 break;
822 case UniformType::Mat2x3:
823 applyUniformHelper<UniformType::Mat2x3>(description, value: v);
824 break;
825 case UniformType::Mat3x2:
826 applyUniformHelper<UniformType::Mat3x2>(description, value: v);
827 break;
828 case UniformType::Mat2x4:
829 applyUniformHelper<UniformType::Mat2x4>(description, value: v);
830 break;
831 case UniformType::Mat4x2:
832 applyUniformHelper<UniformType::Mat4x2>(description, value: v);
833 break;
834 case UniformType::Mat3x4:
835 applyUniformHelper<UniformType::Mat3x4>(description, value: v);
836 break;
837 case UniformType::Mat4x3:
838 applyUniformHelper<UniformType::Mat4x3>(description, value: v);
839 break;
840
841 default:
842 break;
843 }
844}
845
846void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
847{
848 m_glHelper->memoryBarrier(barriers);
849}
850
851GLint GraphicsContext::elementType(GLint type)
852{
853 switch (type) {
854 case GL_FLOAT:
855 case GL_FLOAT_VEC2:
856 case GL_FLOAT_VEC3:
857 case GL_FLOAT_VEC4:
858 return GL_FLOAT;
859
860#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
861 case GL_DOUBLE:
862#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems
863 case GL_DOUBLE_VEC2:
864 case GL_DOUBLE_VEC3:
865 case GL_DOUBLE_VEC4:
866#endif
867 return GL_DOUBLE;
868#endif
869 default:
870 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
871 }
872
873 return GL_INVALID_VALUE;
874}
875
876GLint GraphicsContext::tupleSizeFromType(GLint type)
877{
878 switch (type) {
879 case GL_FLOAT:
880#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
881 case GL_DOUBLE:
882#endif
883 case GL_UNSIGNED_BYTE:
884 case GL_UNSIGNED_INT:
885 break; // fall through
886
887 case GL_FLOAT_VEC2:
888#ifdef GL_DOUBLE_VEC2 // For compiling on pre GL 4.1 systems.
889 case GL_DOUBLE_VEC2:
890#endif
891 return 2;
892
893 case GL_FLOAT_VEC3:
894#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems.
895 case GL_DOUBLE_VEC3:
896#endif
897 return 3;
898
899 case GL_FLOAT_VEC4:
900#ifdef GL_DOUBLE_VEC4 // For compiling on pre GL 4.1 systems.
901 case GL_DOUBLE_VEC4:
902#endif
903 return 4;
904
905 default:
906 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
907 }
908
909 return 1;
910}
911
912GLuint GraphicsContext::byteSizeFromType(GLint type)
913{
914 switch (type) {
915 case GL_FLOAT: return sizeof(float);
916#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
917 case GL_DOUBLE: return sizeof(double);
918#endif
919 case GL_UNSIGNED_BYTE: return sizeof(unsigned char);
920 case GL_UNSIGNED_INT: return sizeof(GLuint);
921
922 case GL_FLOAT_VEC2: return sizeof(float) * 2;
923 case GL_FLOAT_VEC3: return sizeof(float) * 3;
924 case GL_FLOAT_VEC4: return sizeof(float) * 4;
925#ifdef GL_DOUBLE_VEC3 // Required to compile on pre GL 4.1 systems
926 case GL_DOUBLE_VEC2: return sizeof(double) * 2;
927 case GL_DOUBLE_VEC3: return sizeof(double) * 3;
928 case GL_DOUBLE_VEC4: return sizeof(double) * 4;
929#endif
930 default:
931 qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, base: 16);
932 }
933
934 return 0;
935}
936
937GLint GraphicsContext::glDataTypeFromAttributeDataType(Qt3DCore::QAttribute::VertexBaseType dataType)
938{
939 using namespace Qt3DCore;
940
941 switch (dataType) {
942 case QAttribute::Byte:
943 return GL_BYTE;
944 case QAttribute::UnsignedByte:
945 return GL_UNSIGNED_BYTE;
946 case QAttribute::Short:
947 return GL_SHORT;
948 case QAttribute::UnsignedShort:
949 return GL_UNSIGNED_SHORT;
950 case QAttribute::Int:
951 return GL_INT;
952 case QAttribute::UnsignedInt:
953 return GL_UNSIGNED_INT;
954 case QAttribute::HalfFloat:
955#ifdef GL_HALF_FLOAT
956 return GL_HALF_FLOAT;
957#endif
958#if !QT_CONFIG(opengles2) // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
959 case QAttribute::Double:
960 return GL_DOUBLE;
961#endif
962 case QAttribute::Float:
963 break;
964 default:
965 qWarning() << Q_FUNC_INFO << "unsupported dataType:" << dataType;
966 }
967 return GL_FLOAT;
968}
969
970QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
971QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv)
972QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv)
973QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv)
974
975// OpenGL expects int* as values for booleans
976QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv)
977QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv)
978QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv)
979QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv)
980
981QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv)
982QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv)
983QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv)
984QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv)
985
986QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv)
987QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv)
988QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv)
989QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv)
990
991QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv)
992QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv)
993QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv)
994QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv)
995QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv)
996QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv)
997QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv)
998QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv)
999QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv)
1000
1001} // namespace OpenGL
1002} // namespace Render
1003} // namespace Qt3DRender of namespace
1004
1005QT_END_NAMESPACE
1006

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