summaryrefslogtreecommitdiffstats
path: root/src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2018-03-12 08:32:35 +0100
committerPaul Lemire <paul.lemire@kdab.com>2020-02-05 11:33:49 +0100
commit0e115ff000fb294de8519bf5b39beee0d6bfa605 (patch)
treec66c1f19ad5e4b7fc4f3be7951fa74d1d4df64bb /src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp
parentf1f387c22dac8748a7edb1f4aa1ea6dac7dfbdfd (diff)
Make the OpenGL renderer a plugin
By default the QRenderAspect will try to load this plugin Change-Id: Ie55e207fb8e6d0b64f717bbb99699eb669eaa3f2 Task-number: QTBUG-61151 Reviewed-by: Mike Krus <mike.krus@kdab.com>
Diffstat (limited to 'src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp')
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp1028
1 files changed, 1028 insertions, 0 deletions
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp
new file mode 100644
index 000000000..abe11fd4d
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp
@@ -0,0 +1,1028 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "graphicscontext_p.h"
+
+#include <Qt3DRender/qgraphicsapifilter.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <Qt3DRender/private/shader_p.h>
+#include <Qt3DRender/private/material_p.h>
+#include <Qt3DRender/private/buffer_p.h>
+#include <Qt3DRender/private/attribute_p.h>
+#include <Qt3DRender/private/rendertarget_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+#include <Qt3DRender/private/buffermanager_p.h>
+#include <Qt3DRender/private/managers_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <Qt3DRender/private/qbuffer_p.h>
+#include <Qt3DRender/private/attachmentpack_p.h>
+#include <Qt3DRender/private/qbuffer_p.h>
+#include <Qt3DRender/private/renderstateset_p.h>
+#include <QOpenGLShaderProgram>
+#include <glresourcemanagers_p.h>
+#include <graphicshelperinterface_p.h>
+#include <gltexture_p.h>
+#include <rendercommand_p.h>
+#include <renderer_p.h>
+#include <renderbuffer_p.h>
+#include <glshader_p.h>
+
+#if !defined(QT_OPENGL_ES_2)
+#include <QOpenGLFunctions_2_0>
+#include <QOpenGLFunctions_3_2_Core>
+#include <QOpenGLFunctions_3_3_Core>
+#include <QOpenGLFunctions_4_3_Core>
+#include <graphicshelpergl2_p.h>
+#include <graphicshelpergl3_2_p.h>
+#include <graphicshelpergl3_3_p.h>
+#include <graphicshelpergl4_p.h>
+#endif
+#include <graphicshelperes2_p.h>
+#include <graphicshelperes3_p.h>
+#include <graphicshelperes3_1_p.h>
+#include <graphicshelperes3_2_p.h>
+
+#include <QSurface>
+#include <QWindow>
+#include <QOpenGLTexture>
+#include <QOpenGLDebugLogger>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+#ifndef GL_MAX_IMAGE_UNITS
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#endif
+
+namespace {
+
+QOpenGLShader::ShaderType shaderType(Qt3DRender::QShaderProgram::ShaderType type)
+{
+ switch (type) {
+ case Qt3DRender::QShaderProgram::Vertex: return QOpenGLShader::Vertex;
+ case Qt3DRender::QShaderProgram::TessellationControl: return QOpenGLShader::TessellationControl;
+ case Qt3DRender::QShaderProgram::TessellationEvaluation: return QOpenGLShader::TessellationEvaluation;
+ case Qt3DRender::QShaderProgram::Geometry: return QOpenGLShader::Geometry;
+ case Qt3DRender::QShaderProgram::Fragment: return QOpenGLShader::Fragment;
+ case Qt3DRender::QShaderProgram::Compute: return QOpenGLShader::Compute;
+ default: Q_UNREACHABLE();
+ }
+}
+
+} // anonymous namespace
+
+namespace Qt3DRender {
+namespace Render {
+
+namespace {
+
+void logOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage)
+{
+ qDebug() << "OpenGL debug message:" << debugMessage;
+}
+
+} // anonymous
+
+GraphicsContext::GraphicsContext()
+ : m_initialized(false)
+ , m_supportsVAO(false)
+ , m_maxTextureUnits(0)
+ , m_maxImageUnits(0)
+ , m_defaultFBO(0)
+ , m_gl(nullptr)
+ , m_glHelper(nullptr)
+ , m_debugLogger(nullptr)
+ , m_currentVAO(nullptr)
+{
+}
+
+GraphicsContext::~GraphicsContext()
+{
+}
+
+void GraphicsContext::setOpenGLContext(QOpenGLContext* ctx)
+{
+ Q_ASSERT(ctx);
+ m_gl = ctx;
+}
+
+void GraphicsContext::initialize()
+{
+ m_initialized = true;
+
+ Q_ASSERT(m_gl);
+
+ m_gl->functions()->glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &m_maxTextureUnits);
+ qCDebug(Backend) << "context supports" << m_maxTextureUnits << "texture units";
+ m_gl->functions()->glGetIntegerv(GL_MAX_IMAGE_UNITS, &m_maxImageUnits);
+ qCDebug(Backend) << "context supports" << m_maxImageUnits << "image units";
+
+ if (m_gl->format().majorVersion() >= 3) {
+ m_supportsVAO = true;
+ } else {
+ QSet<QByteArray> extensions = m_gl->extensions();
+ m_supportsVAO = extensions.contains(QByteArrayLiteral("GL_OES_vertex_array_object"))
+ || extensions.contains(QByteArrayLiteral("GL_ARB_vertex_array_object"))
+ || extensions.contains(QByteArrayLiteral("GL_APPLE_vertex_array_object"));
+ }
+
+ m_defaultFBO = m_gl->defaultFramebufferObject();
+ qCDebug(Backend) << "VAO support = " << m_supportsVAO;
+}
+
+void GraphicsContext::clearBackBuffer(QClearBuffers::BufferTypeFlags buffers)
+{
+ if (buffers != QClearBuffers::None) {
+ GLbitfield mask = 0;
+
+ if (buffers & QClearBuffers::ColorBuffer)
+ mask |= GL_COLOR_BUFFER_BIT;
+ if (buffers & QClearBuffers::DepthBuffer)
+ mask |= GL_DEPTH_BUFFER_BIT;
+ if (buffers & QClearBuffers::StencilBuffer)
+ mask |= GL_STENCIL_BUFFER_BIT;
+
+ m_gl->functions()->glClear(mask);
+ }
+}
+
+bool GraphicsContext::hasValidGLHelper() const
+{
+ return m_glHelper != nullptr;
+}
+
+bool GraphicsContext::isInitialized() const
+{
+ return m_initialized;
+}
+
+bool GraphicsContext::makeCurrent(QSurface *surface)
+{
+ Q_ASSERT(m_gl);
+ if (!m_gl->makeCurrent(surface)) {
+ qCWarning(Backend) << Q_FUNC_INFO << "makeCurrent failed";
+ return false;
+ }
+
+ initializeHelpers(surface);
+
+ return true;
+}
+
+void GraphicsContext::initializeHelpers(QSurface *surface)
+{
+ // Set the correct GL Helper depending on the surface
+ // If no helper exists, create one
+ m_glHelper = m_glHelpers.value(surface);
+ if (!m_glHelper) {
+ m_glHelper = resolveHighestOpenGLFunctions();
+ m_glHelpers.insert(surface, m_glHelper);
+ }
+}
+
+void GraphicsContext::doneCurrent()
+{
+ Q_ASSERT(m_gl);
+ m_gl->doneCurrent();
+ m_glHelper = nullptr;
+}
+
+// Called by GL Command Thread
+GraphicsContext::ShaderCreationInfo GraphicsContext::createShaderProgram(GLShader *shader)
+{
+ QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
+
+ // Compile shaders
+ const auto shaderCode = shader->shaderCode();
+
+ QString logs;
+ for (int i = QShaderProgram::Vertex; i <= QShaderProgram::Compute; ++i) {
+ const QShaderProgram::ShaderType type = static_cast<QShaderProgram::ShaderType>(i);
+ if (!shaderCode.at(i).isEmpty()) {
+ // Note: logs only return the error but not all the shader code
+ // we could append it
+ if (!shaderProgram->addCacheableShaderFromSourceCode(shaderType(type), shaderCode.at(i)))
+ logs += shaderProgram->log();
+ }
+ }
+
+ // Call glBindFragDataLocation and link the program
+ // Since we are sharing shaders in the backend, we assume that if using custom
+ // fragOutputs, they should all be the same for a given shader
+ bindFragOutputs(shaderProgram->programId(), shader->fragOutputs());
+
+ const bool linkSucceeded = shaderProgram->link();
+ logs += shaderProgram->log();
+
+ // Perform shader introspection
+ introspectShaderInterface(shader);
+
+ ShaderCreationInfo info;
+ info.linkSucceeded = linkSucceeded;
+ info.logs = logs;
+
+ return info;
+}
+
+// That assumes that the shaderProgram in Shader stays the same
+void GraphicsContext::introspectShaderInterface(GLShader *shader)
+{
+ QOpenGLShaderProgram *shaderProgram = shader->shaderProgram();
+ GraphicsHelperInterface *glHelper = resolveHighestOpenGLFunctions();
+ shader->initializeUniforms(glHelper->programUniformsAndLocations(shaderProgram->programId()));
+ shader->initializeAttributes(glHelper->programAttributesAndLocations(shaderProgram->programId()));
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject))
+ shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId()));
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject))
+ shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId()));
+}
+
+
+// Called by Renderer::updateGLResources
+void GraphicsContext::loadShader(Shader *shaderNode,
+ ShaderManager *shaderManager,
+ GLShaderManager *glShaderManager)
+{
+ const Qt3DCore::QNodeId shaderId = shaderNode->peerId();
+ GLShader *glShader = glShaderManager->lookupResource(shaderId);
+
+ // We already have a shader associated with the node
+ if (glShader != nullptr) {
+ // We need to abandon it
+ glShaderManager->abandon(glShader, shaderNode);
+ }
+
+ // We create or adopt an already created glShader
+ glShader = glShaderManager->createOrAdoptExisting(shaderNode);
+
+ const QVector<Qt3DCore::QNodeId> sharedShaderIds = glShaderManager->shaderIdsForProgram(glShader);
+ if (sharedShaderIds.size() == 1) {
+ // Shader in the cache hasn't been loaded yet
+ glShader->setGraphicsContext(this);
+ glShader->setShaderCode(shaderNode->shaderCode());
+ const ShaderCreationInfo loadResult = createShaderProgram(glShader);
+ shaderNode->setStatus(loadResult.linkSucceeded ? QShaderProgram::Ready : QShaderProgram::Error);
+ shaderNode->setLog(loadResult.logs);
+ // Loaded in the sense we tried to load it (and maybe it failed)
+ glShader->setLoaded(true);
+ } else {
+ // Find an already loaded shader that shares the same QOpenGLShaderProgram
+ for (const Qt3DCore::QNodeId sharedShaderId : sharedShaderIds) {
+ if (sharedShaderId != shaderNode->peerId()) {
+ Shader *refShader = shaderManager->lookupResource(sharedShaderId);
+ // We only introspect once per actual OpenGL shader program
+ // rather than once per ShaderNode.
+ shaderNode->initializeFromReference(*refShader);
+ break;
+ }
+ }
+ }
+ shaderNode->unsetDirty();
+ // Ensure we will rebuilt material caches
+ shaderNode->markDirty(AbstractRenderer::AllDirty);
+}
+
+void GraphicsContext::activateDrawBuffers(const AttachmentPack &attachments)
+{
+ const QVector<int> activeDrawBuffers = attachments.getGlDrawBuffers();
+
+ if (m_glHelper->checkFrameBufferComplete()) {
+ if (activeDrawBuffers.size() > 1) {// We need MRT
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::MRT)) {
+ // Set up MRT, glDrawBuffers...
+ m_glHelper->drawBuffers(activeDrawBuffers.size(), activeDrawBuffers.data());
+ }
+ }
+ } else {
+ qWarning() << "FBO incomplete";
+ }
+}
+
+void GraphicsContext::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_glHelper->rasterMode(faceMode, rasterMode);
+}
+
+/*!
+ * \internal
+ * Finds the highest supported opengl version and internally use the most optimized
+ * helper for a given version.
+ */
+GraphicsHelperInterface *GraphicsContext::resolveHighestOpenGLFunctions()
+{
+ Q_ASSERT(m_gl);
+ GraphicsHelperInterface *glHelper = nullptr;
+
+ if (m_gl->isOpenGLES()) {
+ if (m_gl->format().majorVersion() >= 3) {
+ if (m_gl->format().minorVersion() >= 2) {
+ glHelper = new GraphicsHelperES3_2;
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.2 Helper";
+ } else if (m_gl->format().minorVersion() >= 1) {
+ glHelper = new GraphicsHelperES3_1;
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.1 Helper";
+ } else {
+ glHelper = new GraphicsHelperES3();
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES 3.0 Helper";
+ }
+ } else {
+ glHelper = new GraphicsHelperES2();
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL ES2 Helper";
+ }
+ glHelper->initializeHelper(m_gl, nullptr);
+ }
+#ifndef QT_OPENGL_ES_2
+ else {
+ QAbstractOpenGLFunctions *glFunctions = nullptr;
+ if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_4_3_Core>()) != nullptr) {
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 4.3";
+ glHelper = new GraphicsHelperGL4();
+ } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_3_Core>()) != nullptr) {
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.3";
+ glHelper = new GraphicsHelperGL3_3();
+ } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_3_2_Core>()) != nullptr) {
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 3.2";
+ glHelper = new GraphicsHelperGL3_2();
+ } else if ((glFunctions = m_gl->versionFunctions<QOpenGLFunctions_2_0>()) != nullptr) {
+ qCDebug(Backend) << Q_FUNC_INFO << " Building OpenGL 2 Helper";
+ glHelper = new GraphicsHelperGL2();
+ }
+ Q_ASSERT_X(glHelper, "GraphicsContext::resolveHighestOpenGLFunctions", "unable to create valid helper for available OpenGL version");
+ glHelper->initializeHelper(m_gl, glFunctions);
+ }
+#endif
+
+ // Note: at this point we are certain the context (m_gl) is current with a surface
+ const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
+ const bool enableDebugLogging = !debugLoggingMode.isEmpty();
+
+ if (enableDebugLogging && !m_debugLogger) {
+ if (m_gl->hasExtension("GL_KHR_debug")) {
+ qCDebug(Backend) << "Qt3D: Enabling OpenGL debug logging";
+ m_debugLogger.reset(new QOpenGLDebugLogger);
+ if (m_debugLogger->initialize()) {
+ QObject::connect(m_debugLogger.data(), &QOpenGLDebugLogger::messageLogged, &logOpenGLDebugMessage);
+ const QString mode = QString::fromLocal8Bit(debugLoggingMode);
+ m_debugLogger->startLogging(mode.startsWith(QLatin1String("sync"), Qt::CaseInsensitive)
+ ? QOpenGLDebugLogger::SynchronousLogging
+ : QOpenGLDebugLogger::AsynchronousLogging);
+
+ const auto msgs = m_debugLogger->loggedMessages();
+ for (const QOpenGLDebugMessage &msg : msgs)
+ logOpenGLDebugMessage(msg);
+ }
+ } else {
+ qCDebug(Backend) << "Qt3D: OpenGL debug logging requested but GL_KHR_debug not supported";
+ }
+ }
+
+
+ // Set Vendor and Extensions of reference GraphicsApiFilter
+ // TO DO: would that vary like the glHelper ?
+
+ QStringList extensions;
+ const auto exts = m_gl->extensions();
+ for (const QByteArray &ext : exts)
+ extensions << QString::fromUtf8(ext);
+ m_contextInfo.m_major = m_gl->format().version().first;
+ m_contextInfo.m_minor = m_gl->format().version().second;
+ m_contextInfo.m_api = m_gl->isOpenGLES() ? QGraphicsApiFilter::OpenGLES : QGraphicsApiFilter::OpenGL;
+ m_contextInfo.m_profile = static_cast<QGraphicsApiFilter::OpenGLProfile>(m_gl->format().profile());
+ m_contextInfo.m_extensions = extensions;
+ m_contextInfo.m_vendor = QString::fromUtf8(reinterpret_cast<const char *>(m_gl->functions()->glGetString(GL_VENDOR)));
+
+ return glHelper;
+}
+
+const GraphicsApiFilterData *GraphicsContext::contextInfo() const
+{
+ return &m_contextInfo;
+}
+
+bool GraphicsContext::supportsDrawBuffersBlend() const
+{
+ return m_glHelper->supportsFeature(GraphicsHelperInterface::DrawBuffersBlend);
+}
+
+/*!
+ * \internal
+ * Wraps an OpenGL call to glDrawElementsInstanced.
+ * If the call is not supported by the system's OpenGL version,
+ * it is simulated with a loop.
+ */
+void GraphicsContext::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ m_glHelper->drawElementsInstancedBaseVertexBaseInstance(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances,
+ baseVertex,
+ baseInstance);
+}
+
+/*!
+ * \internal
+ * Wraps an OpenGL call to glDrawArraysInstanced.
+ */
+void GraphicsContext::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ m_glHelper->drawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsContext::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance)
+{
+ m_glHelper->drawArraysInstancedBaseInstance(primitiveType,
+ first,
+ count,
+ instances,
+ baseinstance);
+}
+
+/*!
+ * \internal
+ * Wraps an OpenGL call to glDrawElements.
+ */
+void GraphicsContext::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ m_glHelper->drawElements(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ baseVertex);
+}
+
+void GraphicsContext::drawElementsIndirect(GLenum mode,
+ GLenum type,
+ void *indirect)
+{
+ m_glHelper->drawElementsIndirect(mode, type, indirect);
+}
+
+/*!
+ * \internal
+ * Wraps an OpenGL call to glDrawArrays.
+ */
+void GraphicsContext::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_glHelper->drawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsContext::drawArraysIndirect(GLenum mode, void *indirect)
+{
+ m_glHelper->drawArraysIndirect(mode, indirect);
+}
+
+void GraphicsContext::setVerticesPerPatch(GLint verticesPerPatch)
+{
+ m_glHelper->setVerticesPerPatch(verticesPerPatch);
+}
+
+void GraphicsContext::blendEquation(GLenum mode)
+{
+ m_glHelper->blendEquation(mode);
+}
+
+void GraphicsContext::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ m_glHelper->blendFunci(buf, sfactor, dfactor);
+}
+
+void GraphicsContext::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ m_glHelper->blendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha);
+}
+
+void GraphicsContext::alphaTest(GLenum mode1, GLenum mode2)
+{
+ m_glHelper->alphaTest(mode1, mode2);
+}
+
+void GraphicsContext::bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode)
+{
+ m_glHelper->bindFrameBufferObject(fbo, mode);
+}
+
+void GraphicsContext::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_glHelper->depthRange(nearValue, farValue);
+}
+
+void GraphicsContext::depthTest(GLenum mode)
+{
+ m_glHelper->depthTest(mode);
+}
+
+void GraphicsContext::depthMask(GLenum mode)
+{
+ m_glHelper->depthMask(mode);
+}
+
+void GraphicsContext::frontFace(GLenum mode)
+{
+ m_glHelper->frontFace(mode);
+}
+
+void GraphicsContext::bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs)
+{
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::MRT) &&
+ m_glHelper->supportsFeature(GraphicsHelperInterface::BindableFragmentOutputs))
+ m_glHelper->bindFragDataLocation(shader, outputs);
+}
+
+void GraphicsContext::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_glHelper->bindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
+void GraphicsContext::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_glHelper->bindUniformBlock(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsContext::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ m_glHelper->bindShaderStorageBlock(programId, shaderStorageBlockIndex, shaderStorageBlockBinding);
+}
+
+void GraphicsContext::bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer)
+{
+ m_glHelper->bindBufferBase(target, bindingIndex, buffer);
+}
+
+void GraphicsContext::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ m_glHelper->buildUniformBuffer(v, description, buffer);
+}
+
+void GraphicsContext::setMSAAEnabled(bool enabled)
+{
+ m_glHelper->setMSAAEnabled(enabled);
+}
+
+void GraphicsContext::setAlphaCoverageEnabled(bool enabled)
+{
+ m_glHelper->setAlphaCoverageEnabled(enabled);
+}
+
+void GraphicsContext::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ m_glHelper->clearBufferf(drawbuffer, values);
+}
+
+GLuint GraphicsContext::boundFrameBufferObject()
+{
+ return m_glHelper->boundFrameBufferObject();
+}
+
+void GraphicsContext::clearColor(const QColor &color)
+{
+ m_gl->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
+}
+
+void GraphicsContext::clearDepthValue(float depth)
+{
+ m_gl->functions()->glClearDepthf(depth);
+}
+
+void GraphicsContext::clearStencilValue(int stencil)
+{
+ m_gl->functions()->glClearStencil(stencil);
+}
+
+void GraphicsContext::enableClipPlane(int clipPlane)
+{
+ m_glHelper->enableClipPlane(clipPlane);
+}
+
+void GraphicsContext::disableClipPlane(int clipPlane)
+{
+ m_glHelper->disableClipPlane(clipPlane);
+}
+
+void GraphicsContext::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
+{
+ m_glHelper->setClipPlane(clipPlane, normal, distance);
+}
+
+GLint GraphicsContext::maxClipPlaneCount()
+{
+ return m_glHelper->maxClipPlaneCount();
+}
+
+GLint GraphicsContext::maxTextureUnitsCount() const
+{
+ return m_maxTextureUnits;
+}
+
+GLint GraphicsContext::maxImageUnitsCount() const
+{
+ return m_maxImageUnits;
+}
+
+
+void GraphicsContext::enablePrimitiveRestart(int restartIndex)
+{
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::PrimitiveRestart))
+ m_glHelper->enablePrimitiveRestart(restartIndex);
+}
+
+void GraphicsContext::disablePrimitiveRestart()
+{
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::PrimitiveRestart))
+ m_glHelper->disablePrimitiveRestart();
+}
+
+void GraphicsContext::pointSize(bool programmable, GLfloat value)
+{
+ m_glHelper->pointSize(programmable, value);
+}
+
+void GraphicsContext::dispatchCompute(int x, int y, int z)
+{
+ if (m_glHelper->supportsFeature(GraphicsHelperInterface::Compute))
+ m_glHelper->dispatchCompute(x, y, z);
+}
+
+GLboolean GraphicsContext::unmapBuffer(GLenum target)
+{
+ return m_glHelper->unmapBuffer(target);
+}
+
+char *GraphicsContext::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return m_glHelper->mapBuffer(target, size);
+}
+
+void GraphicsContext::enablei(GLenum cap, GLuint index)
+{
+ m_glHelper->enablei(cap, index);
+}
+
+void GraphicsContext::disablei(GLenum cap, GLuint index)
+{
+ m_glHelper->disablei(cap, index);
+}
+
+void GraphicsContext::setSeamlessCubemap(bool enable)
+{
+ m_glHelper->setSeamlessCubemap(enable);
+}
+
+void GraphicsContext::readBuffer(GLenum mode)
+{
+ m_glHelper->readBuffer(mode);
+}
+
+void GraphicsContext::drawBuffer(GLenum mode)
+{
+ m_glHelper->drawBuffer(mode);
+}
+
+void GraphicsContext::drawBuffers(GLsizei n, const int *bufs)
+{
+ m_glHelper->drawBuffers(n, bufs);
+}
+
+void GraphicsContext::applyUniform(const ShaderUniform &description, const UniformValue &v)
+{
+ const UniformType type = m_glHelper->uniformTypeFromGLType(description.m_type);
+
+ switch (type) {
+ case UniformType::Float:
+ // See QTBUG-57510 and uniform_p.h
+ if (v.storedType() == Int) {
+ float value = float(*v.constData<int>());
+ UniformValue floatV(value);
+ applyUniformHelper<UniformType::Float>(description, floatV);
+ } else {
+ applyUniformHelper<UniformType::Float>(description, v);
+ }
+ break;
+ case UniformType::Vec2:
+ applyUniformHelper<UniformType::Vec2>(description, v);
+ break;
+ case UniformType::Vec3:
+ applyUniformHelper<UniformType::Vec3>(description, v);
+ break;
+ case UniformType::Vec4:
+ applyUniformHelper<UniformType::Vec4>(description, v);
+ break;
+
+ case UniformType::Double:
+ applyUniformHelper<UniformType::Double>(description, v);
+ break;
+ case UniformType::DVec2:
+ applyUniformHelper<UniformType::DVec2>(description, v);
+ break;
+ case UniformType::DVec3:
+ applyUniformHelper<UniformType::DVec3>(description, v);
+ break;
+ case UniformType::DVec4:
+ applyUniformHelper<UniformType::DVec4>(description, v);
+ break;
+
+ case UniformType::Sampler:
+ case UniformType::Image:
+ case UniformType::Int:
+ applyUniformHelper<UniformType::Int>(description, v);
+ break;
+ case UniformType::IVec2:
+ applyUniformHelper<UniformType::IVec2>(description, v);
+ break;
+ case UniformType::IVec3:
+ applyUniformHelper<UniformType::IVec3>(description, v);
+ break;
+ case UniformType::IVec4:
+ applyUniformHelper<UniformType::IVec4>(description, v);
+ break;
+
+ case UniformType::UInt:
+ applyUniformHelper<UniformType::UInt>(description, v);
+ break;
+ case UniformType::UIVec2:
+ applyUniformHelper<UniformType::UIVec2>(description, v);
+ break;
+ case UniformType::UIVec3:
+ applyUniformHelper<UniformType::UIVec3>(description, v);
+ break;
+ case UniformType::UIVec4:
+ applyUniformHelper<UniformType::UIVec4>(description, v);
+ break;
+
+ case UniformType::Bool:
+ applyUniformHelper<UniformType::Bool>(description, v);
+ break;
+ case UniformType::BVec2:
+ applyUniformHelper<UniformType::BVec2>(description, v);
+ break;
+ case UniformType::BVec3:
+ applyUniformHelper<UniformType::BVec3>(description, v);
+ break;
+ case UniformType::BVec4:
+ applyUniformHelper<UniformType::BVec4>(description, v);
+ break;
+
+ case UniformType::Mat2:
+ applyUniformHelper<UniformType::Mat2>(description, v);
+ break;
+ case UniformType::Mat3:
+ applyUniformHelper<UniformType::Mat3>(description, v);
+ break;
+ case UniformType::Mat4:
+ applyUniformHelper<UniformType::Mat4>(description, v);
+ break;
+ case UniformType::Mat2x3:
+ applyUniformHelper<UniformType::Mat2x3>(description, v);
+ break;
+ case UniformType::Mat3x2:
+ applyUniformHelper<UniformType::Mat3x2>(description, v);
+ break;
+ case UniformType::Mat2x4:
+ applyUniformHelper<UniformType::Mat2x4>(description, v);
+ break;
+ case UniformType::Mat4x2:
+ applyUniformHelper<UniformType::Mat4x2>(description, v);
+ break;
+ case UniformType::Mat3x4:
+ applyUniformHelper<UniformType::Mat3x4>(description, v);
+ break;
+ case UniformType::Mat4x3:
+ applyUniformHelper<UniformType::Mat4x3>(description, v);
+ break;
+
+ default:
+ break;
+ }
+}
+
+void GraphicsContext::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ m_glHelper->memoryBarrier(barriers);
+}
+
+GLint GraphicsContext::elementType(GLint type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ return GL_FLOAT;
+
+#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
+ case GL_DOUBLE:
+#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems
+ case GL_DOUBLE_VEC2:
+ case GL_DOUBLE_VEC3:
+ case GL_DOUBLE_VEC4:
+#endif
+ return GL_DOUBLE;
+#endif
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
+ }
+
+ return GL_INVALID_VALUE;
+}
+
+GLint GraphicsContext::tupleSizeFromType(GLint type)
+{
+ switch (type) {
+ case GL_FLOAT:
+#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
+ case GL_DOUBLE:
+#endif
+ case GL_UNSIGNED_BYTE:
+ case GL_UNSIGNED_INT:
+ break; // fall through
+
+ case GL_FLOAT_VEC2:
+#ifdef GL_DOUBLE_VEC2 // For compiling on pre GL 4.1 systems.
+ case GL_DOUBLE_VEC2:
+#endif
+ return 2;
+
+ case GL_FLOAT_VEC3:
+#ifdef GL_DOUBLE_VEC3 // For compiling on pre GL 4.1 systems.
+ case GL_DOUBLE_VEC3:
+#endif
+ return 3;
+
+ case GL_FLOAT_VEC4:
+#ifdef GL_DOUBLE_VEC4 // For compiling on pre GL 4.1 systems.
+ case GL_DOUBLE_VEC4:
+#endif
+ return 4;
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
+ }
+
+ return 1;
+}
+
+GLuint GraphicsContext::byteSizeFromType(GLint type)
+{
+ switch (type) {
+ case GL_FLOAT: return sizeof(float);
+#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
+ case GL_DOUBLE: return sizeof(double);
+#endif
+ case GL_UNSIGNED_BYTE: return sizeof(unsigned char);
+ case GL_UNSIGNED_INT: return sizeof(GLuint);
+
+ case GL_FLOAT_VEC2: return sizeof(float) * 2;
+ case GL_FLOAT_VEC3: return sizeof(float) * 3;
+ case GL_FLOAT_VEC4: return sizeof(float) * 4;
+#ifdef GL_DOUBLE_VEC3 // Required to compile on pre GL 4.1 systems
+ case GL_DOUBLE_VEC2: return sizeof(double) * 2;
+ case GL_DOUBLE_VEC3: return sizeof(double) * 3;
+ case GL_DOUBLE_VEC4: return sizeof(double) * 4;
+#endif
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported:" << QString::number(type, 16);
+ }
+
+ return 0;
+}
+
+GLint GraphicsContext::glDataTypeFromAttributeDataType(QAttribute::VertexBaseType dataType)
+{
+ switch (dataType) {
+ case QAttribute::Byte:
+ return GL_BYTE;
+ case QAttribute::UnsignedByte:
+ return GL_UNSIGNED_BYTE;
+ case QAttribute::Short:
+ return GL_SHORT;
+ case QAttribute::UnsignedShort:
+ return GL_UNSIGNED_SHORT;
+ case QAttribute::Int:
+ return GL_INT;
+ case QAttribute::UnsignedInt:
+ return GL_UNSIGNED_INT;
+ case QAttribute::HalfFloat:
+#ifdef GL_HALF_FLOAT
+ return GL_HALF_FLOAT;
+#endif
+#ifndef QT_OPENGL_ES_2 // Otherwise compile error as Qt defines GL_DOUBLE as GL_FLOAT when using ES2
+ case QAttribute::Double:
+ return GL_DOUBLE;
+#endif
+ case QAttribute::Float:
+ break;
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported dataType:" << dataType;
+ }
+ return GL_FLOAT;
+}
+
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Float, float, glUniform1fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec2, float, glUniform2fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec3, float, glUniform3fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Vec4, float, glUniform4fv)
+
+// OpenGL expects int* as values for booleans
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Bool, int, glUniform1iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec2, int, glUniform2iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec3, int, glUniform3iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::BVec4, int, glUniform4iv)
+
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Int, int, glUniform1iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec2, int, glUniform2iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec3, int, glUniform3iv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::IVec4, int, glUniform4iv)
+
+QT3D_UNIFORM_TYPE_IMPL(UniformType::UInt, uint, glUniform1uiv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec2, uint, glUniform2uiv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec3, uint, glUniform3uiv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::UIVec4, uint, glUniform4uiv)
+
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2, float, glUniformMatrix2fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3, float, glUniformMatrix3fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4, float, glUniformMatrix4fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x3, float, glUniformMatrix2x3fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x2, float, glUniformMatrix3x2fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat2x4, float, glUniformMatrix2x4fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x2, float, glUniformMatrix4x2fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat3x4, float, glUniformMatrix3x4fv)
+QT3D_UNIFORM_TYPE_IMPL(UniformType::Mat4x3, float, glUniformMatrix4x3fv)
+
+} // namespace Render
+} // namespace Qt3DRender of namespace
+
+QT_END_NAMESPACE