summaryrefslogtreecommitdiffstats
path: root/src/plugins/renderers/opengl/graphicshelpers
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
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')
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicscontext.cpp1028
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicscontext_p.h264
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2.cpp1034
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2_p.h182
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3.cpp768
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp367
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h87
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp193
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h84
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_p.h108
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp935
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h183
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp1245
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h185
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp1240
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h185
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp1442
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h182
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h203
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/graphicshelpers.pri33
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp306
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h95
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/qgraphicsutils_p.h410
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp1574
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h234
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp225
-rw-r--r--src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h106
27 files changed, 12898 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
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicscontext_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicscontext_p.h
new file mode 100644
index 000000000..07df3e9e4
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicscontext_p.h
@@ -0,0 +1,264 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSCONTEXT_H
+#define QT3DRENDER_RENDER_GRAPHICSCONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
+#include <QOpenGLVertexArrayObject>
+#include <QHash>
+#include <QColor>
+#include <QMatrix4x4>
+#include <QBitArray>
+#include <QImage>
+#include <Qt3DRender/qclearbuffers.h>
+#include <Qt3DRender/private/shader_p.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/qmemorybarrier.h>
+#include <Qt3DRender/private/handle_types_p.h>
+#include <Qt3DRender/private/qgraphicsapifilter_p.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/private/qblitframebuffer_p.h>
+#include <gl_handle_types_p.h>
+#include <glbuffer_p.h>
+#include <shaderparameterpack_p.h>
+#include <graphicshelperinterface_p.h>
+#include <qmath.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLShaderProgram;
+class QAbstractOpenGLFunctions;
+class QOpenGLDebugLogger;
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GraphicsHelperInterface;
+class RenderTarget;
+class AttachmentPack;
+class ShaderManager;
+class GLShader;
+class GLShaderManager;
+
+typedef QPair<QString, int> NamedUniformLocation;
+
+class Q_AUTOTEST_EXPORT GraphicsContext
+{
+public:
+ GraphicsContext();
+ ~GraphicsContext();
+
+ void setOpenGLContext(QOpenGLContext* ctx);
+ QOpenGLContext *openGLContext() { return m_gl; }
+ bool makeCurrent(QSurface *surface);
+ void doneCurrent();
+ bool hasValidGLHelper() const;
+ bool isInitialized() const;
+
+ // Shaders
+ struct ShaderCreationInfo
+ {
+ bool linkSucceeded = false;
+ QString logs;
+ };
+
+ ShaderCreationInfo createShaderProgram(GLShader *shaderNode);
+ void introspectShaderInterface(GLShader *shader);
+ void loadShader(Shader* shader, ShaderManager *shaderManager, GLShaderManager *glShaderManager);
+
+ GLuint defaultFBO() const { return m_defaultFBO; }
+
+ const GraphicsApiFilterData *contextInfo() const;
+
+ // Wrapper methods
+ void clearBackBuffer(QClearBuffers::BufferTypeFlags buffers);
+ void alphaTest(GLenum mode1, GLenum mode2);
+ void bindFramebuffer(GLuint fbo, GraphicsHelperInterface::FBOBindMode mode);
+ void bindBufferBase(GLenum target, GLuint bindingIndex, GLuint buffer);
+ void bindFragOutputs(GLuint shader, const QHash<QString, int> &outputs);
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format);
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding);
+ void blendEquation(GLenum mode);
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor);
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha);
+ GLuint boundFrameBufferObject();
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer);
+ void clearBufferf(GLint drawbuffer, const QVector4D &values);
+ void clearColor(const QColor &color);
+ void clearDepthValue(float depth);
+ void clearStencilValue(int stencil);
+ void depthRange(GLdouble nearValue, GLdouble farValue);
+ void depthMask(GLenum mode);
+ void depthTest(GLenum mode);
+ void disableClipPlane(int clipPlane);
+ void disablei(GLenum cap, GLuint index);
+ void disablePrimitiveRestart();
+ void dispatchCompute(int x, int y, int z);
+ char * mapBuffer(GLenum target, GLsizeiptr size);
+ GLboolean unmapBuffer(GLenum target);
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count);
+ void drawArraysIndirect(GLenum mode,void *indirect);
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances);
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance);
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices, GLint baseVertex);
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect);
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices, GLsizei instances, GLint baseVertex, GLint baseInstance);
+ void enableClipPlane(int clipPlane);
+ void enablei(GLenum cap, GLuint index);
+ void enablePrimitiveRestart(int restartIndex);
+ void frontFace(GLenum mode);
+ GLint maxClipPlaneCount();
+ GLint maxTextureUnitsCount() const;
+ GLint maxImageUnitsCount() const;
+ void pointSize(bool programmable, GLfloat value);
+ void readBuffer(GLenum mode);
+ void drawBuffer(GLenum mode);
+ void drawBuffers(GLsizei n, const int *bufs);
+ void setMSAAEnabled(bool enabled);
+ void setAlphaCoverageEnabled(bool enabled);
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance);
+ void setSeamlessCubemap(bool enable);
+ void setVerticesPerPatch(GLint verticesPerPatch);
+ void memoryBarrier(QMemoryBarrier::Operations barriers);
+ void activateDrawBuffers(const AttachmentPack &attachments);
+ void rasterMode(GLenum faceMode, GLenum rasterMode);
+
+ // Helper methods
+ static GLint elementType(GLint type);
+ static GLint tupleSizeFromType(GLint type);
+ static GLuint byteSizeFromType(GLint type);
+ static GLint glDataTypeFromAttributeDataType(QAttribute::VertexBaseType dataType);
+
+ bool supportsDrawBuffersBlend() const;
+ bool supportsVAO() const { return m_supportsVAO; }
+
+ void initialize();
+ void initializeHelpers(QSurface *surface);
+ GraphicsHelperInterface *resolveHighestOpenGLFunctions();
+
+ bool m_initialized;
+ bool m_supportsVAO;
+ GLint m_maxTextureUnits;
+ GLint m_maxImageUnits;
+ GLuint m_defaultFBO;
+ QOpenGLContext *m_gl;
+ GraphicsHelperInterface *m_glHelper;
+
+ QHash<QSurface *, GraphicsHelperInterface*> m_glHelpers;
+ GraphicsApiFilterData m_contextInfo;
+ QScopedPointer<QOpenGLDebugLogger> m_debugLogger;
+
+ friend class OpenGLVertexArrayObject;
+ OpenGLVertexArrayObject *m_currentVAO;
+
+ void applyUniform(const ShaderUniform &description, const UniformValue &v);
+
+ template<UniformType>
+ void applyUniformHelper(const ShaderUniform &, const UniformValue &) const
+ {
+ Q_ASSERT_X(false, Q_FUNC_INFO, "Uniform: Didn't provide specialized apply() implementation");
+ }
+};
+
+#define QT3D_UNIFORM_TYPE_PROTO(UniformTypeEnum, BaseType, Func) \
+template<> \
+void GraphicsContext::applyUniformHelper<UniformTypeEnum>(const ShaderUniform &description, const UniformValue &value) const;
+
+#define QT3D_UNIFORM_TYPE_IMPL(UniformTypeEnum, BaseType, Func) \
+ template<> \
+ void GraphicsContext::applyUniformHelper<UniformTypeEnum>(const ShaderUniform &description, const UniformValue &value) const \
+{ \
+ const int count = qMin(description.m_size, int(value.byteSize() / description.m_rawByteSize)); \
+ m_glHelper->Func(description.m_location, count, value.constData<BaseType>()); \
+}
+
+
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Float, float, glUniform1fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec2, float, glUniform2fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec3, float, glUniform3fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Vec4, float, glUniform4fv)
+
+// OpenGL expects int* as values for booleans
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Bool, int, glUniform1iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec2, int, glUniform2iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec3, int, glUniform3iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::BVec4, int, glUniform4iv)
+
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Int, int, glUniform1iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec2, int, glUniform2iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec3, int, glUniform3iv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::IVec4, int, glUniform4iv)
+
+QT3D_UNIFORM_TYPE_PROTO(UniformType::UInt, uint, glUniform1uiv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec2, uint, glUniform2uiv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec3, uint, glUniform3uiv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::UIVec4, uint, glUniform4uiv)
+
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2, float, glUniformMatrix2fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3, float, glUniformMatrix3fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4, float, glUniformMatrix4fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2x3, float, glUniformMatrix2x3fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3x2, float, glUniformMatrix3x2fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat2x4, float, glUniformMatrix2x4fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4x2, float, glUniformMatrix4x2fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat3x4, float, glUniformMatrix3x4fv)
+QT3D_UNIFORM_TYPE_PROTO(UniformType::Mat4x3, float, glUniformMatrix4x3fv)
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSCONTEXT_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
new file mode 100644
index 000000000..ba00325b1
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2.cpp
@@ -0,0 +1,1034 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "graphicshelperes2_p.h"
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <private/attachmentpack_p.h>
+#include <qgraphicsutils_p.h>
+#include <renderbuffer_p.h>
+#include <QtGui/private/qopenglextensions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.0+
+#ifndef GL_SAMPLER_3D
+#define GL_SAMPLER_3D 0x8B5F
+#endif
+#ifndef GL_SAMPLER_2D_SHADOW
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#endif
+#ifndef GL_SAMPLER_CUBE_SHADOW
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#endif
+#ifndef GL_SAMPLER_2D_ARRAY
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#endif
+#ifndef GL_SAMPLER_2D_ARRAY_SHADOW
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperES2::GraphicsHelperES2()
+ : m_funcs(0)
+ , m_supportFramebufferBlit(false)
+{
+}
+
+GraphicsHelperES2::~GraphicsHelperES2()
+{
+}
+
+void GraphicsHelperES2::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *)
+{
+ Q_ASSERT(context);
+ m_funcs = context->functions();
+ Q_ASSERT(m_funcs);
+ m_ext.reset(new QOpenGLExtensions(context));
+ if (m_ext->hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit))
+ m_supportFramebufferBlit = true;
+}
+
+void GraphicsHelperES2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
+
+ if (baseVertex != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertex is not supported with OpenGL ES 2";
+
+ for (GLint i = 0; i < instances; i++)
+ drawElements(primitiveType,
+ primitiveCount,
+ indexType,
+ indices);
+}
+
+void GraphicsHelperES2::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ for (GLint i = 0; i < instances; i++)
+ drawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperES2::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL ES 2";
+ for (GLint i = 0; i < instances; i++)
+ drawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperES2::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ if (baseVertex != 0)
+ qWarning() << "glDrawElementsBaseVertex is not supported with OpenGL ES 2";
+ QOpenGLExtensions *xfuncs = static_cast<QOpenGLExtensions *>(m_funcs);
+ if (indexType == GL_UNSIGNED_INT && !xfuncs->hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint)) {
+ static bool warnShown = false;
+ if (!warnShown) {
+ warnShown = true;
+ qWarning("GL_UNSIGNED_INT index type not supported on this system, skipping draw call.");
+ }
+ return;
+ }
+ m_funcs->glDrawElements(primitiveType,
+ primitiveCount,
+ indexType,
+ indices);
+}
+
+void GraphicsHelperES2::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_funcs->glDrawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperES2::drawElementsIndirect(GLenum, GLenum, void *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Indirect Drawing is not supported with OpenGL ES 2";
+}
+
+void GraphicsHelperES2::drawArraysIndirect(GLenum , void *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Indirect Drawing is not supported with OpenGL ES 2";
+}
+
+void GraphicsHelperES2::setVerticesPerPatch(GLint verticesPerPatch)
+{
+ Q_UNUSED(verticesPerPatch);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Tessellation not supported with OpenGL ES 2";
+}
+
+void GraphicsHelperES2::useProgram(GLuint programId)
+{
+ m_funcs->glUseProgram(programId);
+}
+
+QVector<ShaderUniform> GraphicsHelperES2::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ }
+ return uniforms;
+}
+
+QVector<ShaderAttribute> GraphicsHelperES2::programAttributesAndLocations(GLuint programId)
+{
+ QVector<ShaderAttribute> attributes;
+ GLint nbrActiveAttributes = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
+ for (GLint i = 0; i < nbrActiveAttributes; i++) {
+ ShaderAttribute attribute;
+ GLsizei attributeNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
+ attributes.append(attribute);
+ }
+ return attributes;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperES2::programUniformBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ QVector<ShaderUniformBlock> blocks;
+ static bool showWarning = true;
+ if (!showWarning)
+ return blocks;
+ showWarning = false;
+ qWarning() << "UBO are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+ return blocks;
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperES2::programShaderStorageBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ QVector<ShaderStorageBlock> blocks;
+ static bool showWarning = true;
+ if (!showWarning)
+ return blocks;
+ showWarning = false;
+ qWarning() << "SSBO are not supported by OpenGL ES 2.0 (since OpenGL ES 3.1)";
+ return blocks;
+}
+
+void GraphicsHelperES2::vertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
+}
+
+void GraphicsHelperES2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperES2::readBuffer(GLenum mode)
+{
+ Q_UNUSED(mode)
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glReadBuffer not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+void GraphicsHelperES2::drawBuffer(GLenum mode)
+{
+ Q_UNUSED(mode);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glDrawBuffer is not supported with OpenGL ES 2";
+}
+
+void *GraphicsHelperES2::fenceSync()
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+ return nullptr;
+}
+
+void GraphicsHelperES2::clientWaitSync(void *, GLuint64 )
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+void GraphicsHelperES2::waitSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+bool GraphicsHelperES2::wasSyncSignaled(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+ return false;
+}
+
+void GraphicsHelperES2::deleteSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL ES 2.0 (since OpenGL ES 3.0)";
+}
+
+void GraphicsHelperES2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ Q_UNUSED(faceMode);
+ Q_UNUSED(rasterMode);
+ qWarning() << "glPolyonMode is not supported with OpenGL ES";
+}
+
+void GraphicsHelperES2::blendEquation(GLenum mode)
+{
+ m_funcs->glBlendEquation(mode);
+}
+
+void GraphicsHelperES2::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sfactor);
+ Q_UNUSED(dfactor);
+
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glBlendFunci() not supported by OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sRGB);
+ Q_UNUSED(dRGB);
+ Q_UNUSED(sAlpha);
+ Q_UNUSED(dAlpha);
+
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glBlendFuncSeparatei() not supported by OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::alphaTest(GLenum, GLenum)
+{
+ qCWarning(Render::Rendering) << Q_FUNC_INFO << "AlphaTest not available with OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::depthTest(GLenum mode)
+{
+ m_funcs->glEnable(GL_DEPTH_TEST);
+ m_funcs->glDepthFunc(mode);
+}
+
+void GraphicsHelperES2::depthMask(GLenum mode)
+{
+ m_funcs->glDepthMask(mode);
+}
+
+void GraphicsHelperES2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRangef(static_cast<float>(nearValue), static_cast<float>(farValue));
+}
+
+void GraphicsHelperES2::frontFace(GLenum mode)
+{
+ m_funcs->glFrontFace(mode);
+}
+
+void GraphicsHelperES2::setMSAAEnabled(bool enabled)
+{
+ Q_UNUSED(enabled);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "MSAA not available with OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::setAlphaCoverageEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
+ : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+}
+
+GLuint GraphicsHelperES2::createFrameBufferObject()
+{
+ GLuint id;
+ m_funcs->glGenFramebuffers(1, &id);
+ return id;
+}
+
+void GraphicsHelperES2::releaseFrameBufferObject(GLuint frameBufferId)
+{
+ m_funcs->glDeleteFramebuffers(1, &frameBufferId);
+}
+
+void GraphicsHelperES2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode)
+{
+ Q_UNUSED(mode)
+ // For ES2 the spec states for target: The symbolic constant must be GL_FRAMEBUFFER
+ // so mode is ignored and is always set to GL_FRAMEBUFFER
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+}
+
+void GraphicsHelperES2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by ES 2.0 (since ES 3.1)";
+
+}
+
+GLuint GraphicsHelperES2::boundFrameBufferObject()
+{
+ GLint id = 0;
+ m_funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &id);
+ return id;
+}
+
+bool GraphicsHelperES2::checkFrameBufferComplete()
+{
+ return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+bool GraphicsHelperES2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ // Use a renderbuffer for depth or stencil attachments since this is
+ // problematic before GLES 3.2. Keep using textures for everything else.
+ // For ES2 individual Depth and Stencil buffers need to be an option because
+ // DepthStencil is an extension.
+ return attachment.m_point == QRenderTargetOutput::DepthStencil ||
+ attachment.m_point == QRenderTargetOutput::Depth ||
+ attachment.m_point == QRenderTargetOutput::Stencil;
+}
+
+void GraphicsHelperES2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_COLOR_ATTACHMENT0;
+
+ if (attachment.m_point == QRenderTargetOutput::Color0)
+ attr = GL_COLOR_ATTACHMENT0;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+ else
+ qCritical() << "Unsupported FBO attachment OpenGL ES 2.0";
+
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL ES 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
+ texture->bind();
+ if (target == QOpenGLTexture::Target2D)
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
+ else if (target == QOpenGLTexture::TargetCubeMap)
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ qCritical() << "Unsupported Texture FBO attachment format";
+ texture->release();
+}
+
+void GraphicsHelperES2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ if (attachment.m_point != QRenderTargetOutput::DepthStencil &&
+ attachment.m_point != QRenderTargetOutput::Depth &&
+ attachment.m_point != QRenderTargetOutput::Stencil) {
+ qCritical() << "Renderbuffers only supported for combined depth-stencil, depth, or stencil, but got attachment point"
+ << attachment.m_point;
+ return;
+ }
+
+ renderBuffer->bind();
+ if (attachment.m_point == QRenderTargetOutput::DepthStencil ||
+ attachment.m_point == QRenderTargetOutput::Depth)
+ m_funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->renderBufferId());
+ if (attachment.m_point == QRenderTargetOutput::DepthStencil ||
+ attachment.m_point == QRenderTargetOutput::Stencil)
+ m_funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderBuffer->renderBufferId());
+ renderBuffer->release();
+}
+
+bool GraphicsHelperES2::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case RenderBufferDimensionRetrieval:
+ return true;
+ case BlitFramebuffer:
+ return m_supportFramebufferBlit;
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperES2::drawBuffers(GLsizei, const int *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "drawBuffers is not supported by ES 2.0";
+}
+
+void GraphicsHelperES2::bindFragDataLocation(GLuint , const QHash<QString, int> &)
+{
+ qCritical() << "bindFragDataLocation is not supported by ES 2.0";
+}
+
+void GraphicsHelperES2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(uniformBlockIndex);
+ Q_UNUSED(uniformBlockBinding);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "UBO are not supported by ES 2.0 (since ES 3.0)";
+}
+
+void GraphicsHelperES2::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(shaderStorageBlockIndex);
+ Q_UNUSED(shaderStorageBlockBinding);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "SSBO are not supported by ES 2.0 (since ES 3.1)";
+}
+
+void GraphicsHelperES2::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ Q_UNUSED(target);
+ Q_UNUSED(index);
+ Q_UNUSED(buffer);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "bindBufferBase is not supported by ES 2.0 (since ES 3.0)";
+}
+
+void GraphicsHelperES2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ Q_UNUSED(v);
+ Q_UNUSED(description);
+ Q_UNUSED(buffer);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "UBO are not supported by ES 2.0 (since ES 3.0)";
+}
+
+uint GraphicsHelperES2::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ rawByteSize = 4;
+ break;
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void GraphicsHelperES2::enableClipPlane(int)
+{
+}
+
+void GraphicsHelperES2::disableClipPlane(int)
+{
+}
+
+void GraphicsHelperES2::setClipPlane(int, const QVector3D &, float)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Clip planes not supported by OpenGL ES 2.0";
+}
+
+GLint GraphicsHelperES2::maxClipPlaneCount()
+{
+ return 0;
+}
+
+void GraphicsHelperES2::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ Q_UNUSED(barriers);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "memory barrier is not supported by OpenGL ES 2.0 (since 4.3)";
+}
+
+void GraphicsHelperES2::enablePrimitiveRestart(int)
+{
+}
+
+void GraphicsHelperES2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
+void GraphicsHelperES2::disablePrimitiveRestart()
+{
+}
+
+void GraphicsHelperES2::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ Q_UNUSED(drawbuffer);
+ Q_UNUSED(values);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glClearBuffer*() not supported by OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::pointSize(bool programmable, GLfloat value)
+{
+ // If this is not a reset to default values, print a warning
+ if (programmable || !qFuzzyCompare(value, 1.0f)) {
+ static bool warned = false;
+ if (!warned) {
+ qWarning() << "glPointSize() and GL_PROGRAM_POINT_SIZE are not supported by ES 2.0";
+ warned = true;
+ }
+ }
+}
+
+void GraphicsHelperES2::enablei(GLenum cap, GLuint index)
+{
+ Q_UNUSED(cap);
+ Q_UNUSED(index);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glEnablei() not supported by OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::disablei(GLenum cap, GLuint index)
+{
+ Q_UNUSED(cap);
+ Q_UNUSED(index);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glDisablei() not supported by OpenGL ES 2.0";
+}
+
+void GraphicsHelperES2::setSeamlessCubemap(bool enable)
+{
+ Q_UNUSED(enable);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "GL_TEXTURE_CUBE_MAP_SEAMLESS not supported by OpenGL ES 2.0";
+}
+
+QSize GraphicsHelperES2::getRenderBufferDimensions(GLuint renderBufferId)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ return QSize(width, height);
+}
+
+QSize GraphicsHelperES2::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+{
+ Q_UNUSED(textureId);
+ Q_UNUSED(target);
+ Q_UNUSED(level);
+ qCritical() << "getTextureDimensions is not supported by ES 2.0";
+ return QSize(0, 0);
+}
+
+void GraphicsHelperES2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ Q_UNUSED(wx);
+ Q_UNUSED(wy);
+ Q_UNUSED(wz);
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Compute Shaders are not supported by ES 2.0 (since ES 3.1)";
+}
+
+char *GraphicsHelperES2::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ Q_UNUSED(target);
+ Q_UNUSED(size);
+ static bool showWarning = true;
+ if (!showWarning)
+ return nullptr;
+ showWarning = false;
+ qWarning() << "Map buffer is not a core requirement for ES 2.0";
+ return nullptr;
+}
+
+GLboolean GraphicsHelperES2::unmapBuffer(GLenum target)
+{
+ Q_UNUSED(target);
+ static bool showWarning = true;
+ if (!showWarning)
+ return false;
+ showWarning = false;
+ qWarning() << "unMap buffer is not a core requirement for ES 2.0";
+ return false;
+}
+
+void GraphicsHelperES2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform1fv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform2fv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform3fv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform4fv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform1iv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform2iv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform3iv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform4iv(location, count, values);
+}
+
+void GraphicsHelperES2::glUniform1uiv(GLint , GLsizei , const GLuint *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniform1uiv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniform2uiv(GLint , GLsizei , const GLuint *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniform2uiv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniform3uiv(GLint , GLsizei , const GLuint *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniform3uiv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniform4uiv(GLint , GLsizei , const GLuint *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniform4uiv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2fv(location, count, false, values);
+}
+
+void GraphicsHelperES2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3fv(location, count, false, values);
+}
+
+void GraphicsHelperES2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4fv(location, count, false, values);
+}
+
+void GraphicsHelperES2::glUniformMatrix2x3fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix2x3fv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix3x2fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix3x2fv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix2x4fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix2x4fv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix4x2fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix4x2fv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix3x4fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix3x4fv not supported by ES 2";
+}
+
+void GraphicsHelperES2::glUniformMatrix4x3fv(GLint , GLsizei , const GLfloat *)
+{
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "glUniformMatrix4x3fv not supported by ES 2";
+}
+
+UniformType GraphicsHelperES2::uniformTypeFromGLType(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ return UniformType::Float;
+ case GL_FLOAT_VEC2:
+ return UniformType::Vec2;
+ case GL_FLOAT_VEC3:
+ return UniformType::Vec3;
+ case GL_FLOAT_VEC4:
+ return UniformType::Vec4;
+ case GL_FLOAT_MAT2:
+ return UniformType::Mat2;
+ case GL_FLOAT_MAT3:
+ return UniformType::Mat3;
+ case GL_FLOAT_MAT4:
+ return UniformType::Mat4;
+ case GL_INT:
+ return UniformType::Int;
+ case GL_INT_VEC2:
+ return UniformType::IVec2;
+ case GL_INT_VEC3:
+ return UniformType::IVec3;
+ case GL_INT_VEC4:
+ return UniformType::IVec4;
+ case GL_BOOL:
+ return UniformType::Bool;
+ case GL_BOOL_VEC2:
+ return UniformType::BVec2;
+ case GL_BOOL_VEC3:
+ return UniformType::BVec3;
+ case GL_BOOL_VEC4:
+ return UniformType::BVec4;
+
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ return UniformType::Sampler;
+ default:
+ Q_UNREACHABLE();
+ return UniformType::Float;
+ }
+}
+
+void GraphicsHelperES2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ if (!m_supportFramebufferBlit) {
+ static bool showWarning = true;
+ if (!showWarning)
+ return;
+ showWarning = false;
+ qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+ } else
+ m_ext->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
new file mode 100644
index 000000000..902bd5fb2
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes2_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERES2_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERES2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperinterface_p.h>
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLExtensions;
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsHelperES2 : public GraphicsHelperInterface
+{
+public:
+ GraphicsHelperES2();
+ virtual ~GraphicsHelperES2();
+
+ // QGraphicHelperInterface interface
+ void alphaTest(GLenum mode1, GLenum mode2) override;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blendEquation(GLenum mode) override;
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ GLuint boundFrameBufferObject() override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ bool checkFrameBufferComplete() override;
+ void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
+ GLuint createFrameBufferObject() override;
+ void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
+ void depthTest(GLenum mode) override;
+ void disableClipPlane(int clipPlane) override;
+ void disablei(GLenum cap, GLuint index) override;
+ void disablePrimitiveRestart() override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLint baseVertex = 0) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void enableClipPlane(int clipPlane) override;
+ void enablei(GLenum cap, GLuint index) override;
+ void enablePrimitiveRestart(int primitiveRestartIndex) override;
+ void enableVertexAttributeArray(int location) override;
+ void frontFace(GLenum mode) override;
+ QSize getRenderBufferDimensions(GLuint renderBufferId) override;
+ QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ void pointSize(bool programmable, GLfloat value) override;
+ GLint maxClipPlaneCount() override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+ void releaseFrameBufferObject(GLuint frameBufferId) override;
+ void setMSAAEnabled(bool enable) override;
+ void setAlphaCoverageEnabled(bool enable) override;
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance) override;
+ void setSeamlessCubemap(bool enable) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ bool supportsFeature(Feature feature) const override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void useProgram(GLuint programId) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ void glUniform1iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform2iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform3iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform4iv(GLint location, GLsizei count, const GLint *value) override;
+
+ void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) override;
+
+ void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+
+protected:
+ QOpenGLFunctions *m_funcs;
+ bool m_supportFramebufferBlit;
+ QScopedPointer<QOpenGLExtensions> m_ext;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERES2_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3.cpp
new file mode 100644
index 000000000..6e299199f
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3.cpp
@@ -0,0 +1,768 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Svenn-Arne Dragly.
+** 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 "graphicshelperes3_p.h"
+#include <private/attachmentpack_p.h>
+#include <qgraphicsutils_p.h>
+#include <private/renderlogging_p.h>
+#include <QOpenGLExtraFunctions>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.0+
+#ifndef GL_SAMPLER_3D
+#define GL_SAMPLER_3D 0x8B5F
+#endif
+#ifndef GL_SAMPLER_2D_SHADOW
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#endif
+#ifndef GL_SAMPLER_CUBE_SHADOW
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#endif
+#ifndef GL_SAMPLER_2D_ARRAY
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#endif
+#ifndef GL_SAMPLER_2D_ARRAY_SHADOW
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#endif
+#ifndef GL_FLOAT_MAT2x3
+#define GL_FLOAT_MAT2x3 0x8B65
+#endif
+#ifndef GL_FLOAT_MAT2x4
+#define GL_FLOAT_MAT2x4 0x8B66
+#endif
+#ifndef GL_FLOAT_MAT3x2
+#define GL_FLOAT_MAT3x2 0x8B67
+#endif
+#ifndef GL_FLOAT_MAT3x4
+#define GL_FLOAT_MAT3x4 0x8B68
+#endif
+#ifndef GL_FLOAT_MAT4x2
+#define GL_FLOAT_MAT4x2 0x8B69
+#endif
+#ifndef GL_FLOAT_MAT4x3
+#define GL_FLOAT_MAT4x3 0x8B6A
+#endif
+#ifndef GL_UNSIGNED_INT_VEC2
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#endif
+#ifndef GL_UNSIGNED_INT_VEC3
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#endif
+#ifndef GL_UNSIGNED_INT_VEC4
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#endif
+#ifndef GL_INT_SAMPLER_2D
+#define GL_INT_SAMPLER_2D 0x8DCA
+#endif
+#ifndef GL_INT_SAMPLER_3D
+#define GL_INT_SAMPLER_3D 0x8DCB
+#endif
+#ifndef GL_INT_SAMPLER_CUBE
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#endif
+#ifndef GL_INT_SAMPLER_2D_ARRAY
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_2D
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_3D
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_CUBE
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_2D_ARRAY
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#endif
+
+#ifndef GL_ACTIVE_UNIFORM_BLOCKS
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#endif
+#ifndef GL_UNIFORM_BLOCK_INDEX
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#endif
+#ifndef GL_UNIFORM_OFFSET
+#define GL_UNIFORM_OFFSET 0x8A3B
+#endif
+#ifndef GL_UNIFORM_ARRAY_STRIDE
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#endif
+#ifndef GL_UNIFORM_MATRIX_STRIDE
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#endif
+#ifndef GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#endif
+#ifndef GL_UNIFORM_BLOCK_BINDING
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#endif
+#ifndef GL_UNIFORM_BLOCK_DATA_SIZE
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#endif
+
+#ifndef GL_SIGNALED
+#define GL_SIGNALED 0x9119
+#endif
+
+#ifndef GL_SYNC_STATUS
+#define GL_SYNC_STATUS 0x9114
+#endif
+
+#ifndef GL_TIMEOUT_IGNORED
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
+#endif
+
+#ifndef GL_SYNC_GPU_COMMANDS_COMPLETE
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#endif
+
+#ifndef GL_SYNC_FLUSH_COMMANDS_BIT
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperES3::GraphicsHelperES3()
+{
+}
+
+GraphicsHelperES3::~GraphicsHelperES3()
+{
+}
+
+void GraphicsHelperES3::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *functions)
+{
+ GraphicsHelperES2::initializeHelper(context, functions);
+ m_extraFuncs = context->extraFunctions();
+ Q_ASSERT(m_extraFuncs);
+}
+
+void GraphicsHelperES3::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 3";
+
+ if (baseVertex != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertex is not supported with OpenGL ES 3";
+
+ m_extraFuncs->glDrawElementsInstanced(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances);
+}
+
+void GraphicsHelperES3::vertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ m_extraFuncs->glVertexAttribDivisor(index, divisor);
+}
+
+void GraphicsHelperES3::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_extraFuncs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperES3::drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances)
+{
+ m_extraFuncs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperES3::readBuffer(GLenum mode)
+{
+ m_extraFuncs->glReadBuffer(mode);
+}
+
+void GraphicsHelperES3::drawBuffer(GLenum mode)
+{
+ Q_UNUSED(mode);
+ qWarning() << "glDrawBuffer is not supported with OpenGL ES 3";
+}
+
+void GraphicsHelperES3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_COLOR_ATTACHMENT0;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+ else
+ qCritical() << "Unsupported FBO attachment OpenGL ES 3.0";
+
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL ES 3.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
+ texture->bind();
+ if (target == QOpenGLTexture::Target2D)
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
+ else if (target == QOpenGLTexture::TargetCubeMap)
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ qCritical() << "Unsupported Texture FBO attachment format";
+ texture->release();
+}
+
+void GraphicsHelperES3::bindFrameBufferObject(GLuint frameBufferId, GraphicsHelperInterface::FBOBindMode mode)
+{
+ switch (mode) {
+ case FBODraw:
+ m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBORead:
+ m_funcs->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBOReadAndDraw:
+ default:
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+ return;
+ }
+}
+
+bool GraphicsHelperES3::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case RenderBufferDimensionRetrieval:
+ case MRT:
+ case BlitFramebuffer:
+ case UniformBufferObject:
+ case MapBuffer:
+ case Fences:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperES3::drawBuffers(GLsizei n, const int *bufs)
+{
+ QVarLengthArray<GLenum, 16> drawBufs(n);
+
+ for (int i = 0; i < n; i++)
+ drawBufs[i] = GL_COLOR_ATTACHMENT0 + bufs[i];
+ m_extraFuncs->glDrawBuffers(n, drawBufs.constData());
+}
+
+UniformType GraphicsHelperES3::uniformTypeFromGLType(GLenum glType)
+{
+ switch (glType) {
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ return UniformType::Sampler;
+ default:
+ return GraphicsHelperES2::uniformTypeFromGLType(glType);
+ }
+}
+
+uint GraphicsHelperES3::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT2x4:
+ rawByteSize = matrixStride ? 2 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT4x2:
+ rawByteSize = matrixStride ? 4 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT2x3:
+ rawByteSize = matrixStride ? 2 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT3x2:
+ rawByteSize = matrixStride ? 3 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_FLOAT_MAT4x3:
+ rawByteSize = matrixStride ? 4 * matrixStride : 48;
+ break;
+
+ case GL_FLOAT_MAT3x4:
+ rawByteSize = matrixStride ? 3 * matrixStride : 48;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_UNSIGNED_INT:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ rawByteSize = 4;
+ break;
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void *GraphicsHelperES3::fenceSync()
+{
+ return m_extraFuncs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperES3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_extraFuncs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperES3::waitSync(void *sync)
+{
+ m_extraFuncs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperES3::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_extraFuncs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperES3::deleteSync(void *sync)
+{
+ m_extraFuncs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
+void GraphicsHelperES3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_extraFuncs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+void GraphicsHelperES3::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ m_extraFuncs->glBindBufferBase(target, index, buffer);
+}
+
+bool GraphicsHelperES3::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ // Use a renderbuffer for combined depth+stencil attachments since this is
+ // problematic before GLES 3.2. Keep using textures for everything else.
+ return attachment.m_point == QRenderTargetOutput::DepthStencil;
+}
+
+void GraphicsHelperES3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_extraFuncs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsHelperES3::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+
+ case GL_FLOAT: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_FLOAT_VEC2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_FLOAT_VEC3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_FLOAT_VEC4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 3);
+ break;
+ }
+
+ case GL_INT: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_INT_VEC2: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_INT_VEC3: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_INT_VEC4: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_UNSIGNED_INT: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC2: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC3: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC4: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_BOOL: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_BOOL_VEC2: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_BOOL_VEC3: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_BOOL_VEC4: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ // note: only GLES 3.0 supported types, not the same as OpenGL proper
+ // (also, no MS samplers before ES 3.1)
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name;
+ break;
+ }
+}
+
+char *GraphicsHelperES3::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return static_cast<char*>(m_extraFuncs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+}
+
+GLboolean GraphicsHelperES3::unmapBuffer(GLenum target)
+{
+ return m_extraFuncs->glUnmapBuffer(target);
+}
+
+QVector<ShaderUniform> GraphicsHelperES3::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
+ m_extraFuncs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_MATRIX_STRIDE, &uniform.m_matrixStride);
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ qCDebug(Render::Rendering) << uniform.m_name << "size" << uniform.m_size
+ << " offset" << uniform.m_offset
+ << " rawSize" << uniform.m_rawByteSize;
+ }
+
+ return uniforms;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperES3::programUniformBlocks(GLuint programId)
+{
+ QVector<ShaderUniformBlock> blocks;
+ GLint nbrActiveUniformsBlocks = 0;
+ m_extraFuncs->glGetProgramiv(programId, GL_ACTIVE_UNIFORM_BLOCKS, &nbrActiveUniformsBlocks);
+ blocks.reserve(nbrActiveUniformsBlocks);
+ for (GLint i = 0; i < nbrActiveUniformsBlocks; i++) {
+ QByteArray uniformBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderUniformBlock uniformBlock;
+ m_extraFuncs->glGetActiveUniformBlockName(programId, i, 256, &length, uniformBlockName.data());
+ uniformBlock.m_name = QString::fromUtf8(uniformBlockName.left(length));
+ uniformBlock.m_index = i;
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &uniformBlock.m_activeUniformsCount);
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_BINDING, &uniformBlock.m_binding);
+ m_extraFuncs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlock.m_size);
+ blocks.append(uniformBlock);
+ }
+ return blocks;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp
new file mode 100644
index 000000000..dc042b0c6
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1.cpp
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://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 "graphicshelperes3_1_p.h"
+#include <qgraphicsutils_p.h>
+#include <QOpenGLExtraFunctions>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.1+
+#ifndef GL_SAMPLER_2D_MULTISAMPLE
+#define GL_SAMPLER_2D_MULTISAMPLE 0x9108
+#endif
+#ifndef GL_INT_SAMPLER_2D_MULTISAMPLE
+#define GL_INT_SAMPLER_2D_MULTISAMPLE 0x9109
+#endif
+#ifndef GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE
+#define GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE 0x910A
+#endif
+#ifndef GL_ACTIVE_RESOURCES
+#define GL_ACTIVE_RESOURCES 0x92F5
+#endif
+#ifndef GL_BUFFER_BINDING
+#define GL_BUFFER_BINDING 0x9302
+#endif
+#ifndef GL_BUFFER_DATA_SIZE
+#define GL_BUFFER_DATA_SIZE 0x9303
+#endif
+#ifndef GL_NUM_ACTIVE_VARIABLES
+#define GL_NUM_ACTIVE_VARIABLES 0x9304
+#endif
+#ifndef GL_SHADER_STORAGE_BLOCK
+#define GL_SHADER_STORAGE_BLOCK 0x92E6
+#endif
+#ifndef GL_ALL_BARRIER_BITS
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+#endif
+#ifndef GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#endif
+#ifndef GL_ELEMENT_ARRAY_BARRIER_BIT
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#endif
+#ifndef GL_UNIFORM_BARRIER_BIT
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#endif
+#ifndef GL_TEXTURE_FETCH_BARRIER_BIT
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#endif
+#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#endif
+#ifndef GL_COMMAND_BARRIER_BIT
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#endif
+#ifndef GL_PIXEL_BUFFER_BARRIER_BIT
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#endif
+#ifndef GL_TEXTURE_UPDATE_BARRIER_BIT
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#endif
+#ifndef GL_BUFFER_UPDATE_BARRIER_BIT
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#endif
+#ifndef GL_FRAMEBUFFER_BARRIER_BIT
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#endif
+#ifndef GL_TRANSFORM_FEEDBACK_BARRIER_BIT
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#endif
+#ifndef GL_ATOMIC_COUNTER_BARRIER_BIT
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#endif
+#ifndef GL_SHADER_STORAGE_BARRIER_BIT
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+#endif
+#ifndef GL_IMAGE_2D
+#define GL_IMAGE_2D 0x904D
+#endif
+#ifndef GL_IMAGE_3D
+#define GL_IMAGE_3D 0x904E
+#endif
+#ifndef GL_IMAGE_CUBE
+#define GL_IMAGE_CUBE 0x9050
+#endif
+#ifndef GL_IMAGE_2D_ARRAY
+#define GL_IMAGE_2D_ARRAY 0x9053
+#endif
+#ifndef GL_INT_IMAGE_2D
+#define GL_INT_IMAGE_2D 0x9058
+#endif
+#ifndef GL_INT_IMAGE_3D
+#define GL_INT_IMAGE_3D 0x9059
+#endif
+#ifndef GL_INT_IMAGE_CUBE
+#define GL_INT_IMAGE_CUBE 0x905B
+#endif
+#ifndef GL_INT_IMAGE_2D_ARRAY
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_2D
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_3D
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_CUBE
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_2D_ARRAY
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#endif
+
+
+namespace Qt3DRender {
+namespace Render {
+
+namespace {
+
+GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::Operations barriers)
+{
+ GLbitfield bits = 0;
+
+ if (barriers.testFlag(QMemoryBarrier::All)) {
+ bits |= GL_ALL_BARRIER_BITS;
+ return bits;
+ }
+
+ if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray))
+ bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ElementArray))
+ bits |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::Uniform))
+ bits |= GL_UNIFORM_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TextureFetch))
+ bits |= GL_TEXTURE_FETCH_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess))
+ bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::Command))
+ bits |= GL_COMMAND_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::PixelBuffer))
+ bits |= GL_PIXEL_BUFFER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TextureUpdate))
+ bits |= GL_TEXTURE_UPDATE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::BufferUpdate))
+ bits |= GL_BUFFER_UPDATE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::FrameBuffer))
+ bits |= GL_FRAMEBUFFER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TransformFeedback))
+ bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::AtomicCounter))
+ bits |= GL_ATOMIC_COUNTER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ShaderStorage))
+ bits |= GL_SHADER_STORAGE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::QueryBuffer))
+ qWarning() << "QueryBuffer barrier not supported by ES 3.1";
+
+ return bits;
+}
+
+} // anonymous
+
+
+GraphicsHelperES3_1::GraphicsHelperES3_1()
+{
+}
+
+GraphicsHelperES3_1::~GraphicsHelperES3_1()
+{
+}
+
+bool GraphicsHelperES3_1::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case GraphicsHelperInterface::Compute:
+ case GraphicsHelperInterface::ShaderStorageObject:
+ case GraphicsHelperInterface::IndirectDrawing:
+ case GraphicsHelperInterface::ShaderImage:
+ return true;
+ default:
+ break;
+ }
+ return GraphicsHelperES3::supportsFeature(feature);
+}
+
+void GraphicsHelperES3_1::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_extraFuncs->glBindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
+void GraphicsHelperES3_1::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ m_extraFuncs->glDispatchCompute(wx, wy, wz);
+}
+
+void GraphicsHelperES3_1::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ m_extraFuncs->glMemoryBarrier(memoryBarrierGLBitfield(barriers));
+}
+
+void GraphicsHelperES3_1::drawArraysIndirect(GLenum mode, void *indirect)
+{
+ m_extraFuncs->glDrawArraysIndirect(mode, indirect);
+}
+
+void GraphicsHelperES3_1::drawElementsIndirect(GLenum mode, GLenum type, void *indirect)
+{
+ m_extraFuncs->glDrawElementsIndirect(mode, type, indirect);
+}
+
+void GraphicsHelperES3_1::bindShaderStorageBlock(GLuint , GLuint , GLuint )
+{
+ // ES 3.1 has no API for that, bindings have to be specified directly in the shader
+ // with layout(std430, binding = 3)
+ qWarning() << "ES 3.1 has no bindShaderStorageBlock API, it uses binding declaration from the shader storage block";
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperES3_1::programShaderStorageBlocks(GLuint programId)
+{
+ QVector<ShaderStorageBlock> blocks;
+ GLint nbrActiveShaderStorageBlocks = 0;
+ m_extraFuncs->glGetProgramInterfaceiv(programId, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &nbrActiveShaderStorageBlocks);
+ blocks.reserve(nbrActiveShaderStorageBlocks);
+ for (GLint i = 0; i < nbrActiveShaderStorageBlocks; ++i) {
+ QByteArray storageBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderStorageBlock storageBlock;
+ m_extraFuncs->glGetProgramResourceName(programId, GL_SHADER_STORAGE_BLOCK, i, 256, &length, storageBlockName.data());
+ storageBlock.m_index = i;
+ storageBlock.m_name = QString::fromUtf8(storageBlockName.left(length));
+ GLenum prop = GL_BUFFER_BINDING;
+ m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_binding);
+ prop = GL_BUFFER_DATA_SIZE;
+ m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_size);
+ prop = GL_NUM_ACTIVE_VARIABLES;
+ m_extraFuncs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_activeVariablesCount);
+ blocks.push_back(storageBlock);
+ }
+ return blocks;
+}
+
+UniformType GraphicsHelperES3_1::uniformTypeFromGLType(GLenum glType)
+{
+ switch (glType) {
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ return UniformType::Sampler;
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ return UniformType::Image;
+
+ default:
+ return GraphicsHelperES3::uniformTypeFromGLType(glType);
+ }
+}
+
+uint GraphicsHelperES3_1::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+
+ switch (description.m_type) {
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ rawByteSize = 4;
+ break;
+
+ default:
+ rawByteSize = GraphicsHelperES3::uniformByteSize(description);
+ break;
+ }
+
+ return rawByteSize;
+}
+
+void GraphicsHelperES3_1::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ GraphicsHelperES3::buildUniformBuffer(v, description, buffer);
+ break;
+ }
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h
new file mode 100644
index 000000000..7eab61c60
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_1_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: http://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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERES3_1_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERES3_1_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperes3_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsHelperES3_1 : public GraphicsHelperES3
+{
+public:
+ GraphicsHelperES3_1();
+ ~GraphicsHelperES3_1();
+
+ bool supportsFeature(Feature feature) const override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+
+ // QGraphicHelperInterface interface
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERES3_1_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp
new file mode 100644
index 000000000..9d0988410
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2.cpp
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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 "graphicshelperes3_2_p.h"
+#include <QOpenGLExtraFunctions>
+#include <Qt3DRender/qrendertargetoutput.h>
+#include <private/attachmentpack_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+#ifndef GL_DEPTH_STENCIL_ATTACHMENT
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#endif
+
+#ifndef GL_PATCH_VERTICES
+#define GL_PATCH_VERTICES 36466
+#endif
+
+#ifndef GL_IMAGE_BUFFER
+#define GL_IMAGE_BUFFER 0x9051
+#endif
+#ifndef GL_IMAGE_CUBE_MAP_ARRAY
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#endif
+#ifndef GL_INT_IMAGE_BUFFER
+#define GL_INT_IMAGE_BUFFER 0x905C
+#endif
+#ifndef GL_INT_IMAGE_CUBE_MAP_ARRAY
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_BUFFER
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#endif
+#ifndef GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperES3_2::GraphicsHelperES3_2()
+{
+}
+
+GraphicsHelperES3_2::~GraphicsHelperES3_2()
+{
+}
+
+bool GraphicsHelperES3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case GraphicsHelperInterface::Tessellation:
+ return true;
+ default:
+ break;
+ }
+ return GraphicsHelperES3_1::supportsFeature(feature);
+}
+
+bool GraphicsHelperES3_2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ // This is first ES version where we have glFramebufferTexture, so
+ // attaching a D24S8 texture to the combined depth-stencil attachment point
+ // should work.
+ return false;
+}
+
+void GraphicsHelperES3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_COLOR_ATTACHMENT0;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::DepthStencil)
+ attr = GL_DEPTH_STENCIL_ATTACHMENT;
+ else
+ qCritical() << "Unsupported FBO attachment OpenGL ES 3.2";
+
+ const QOpenGLTexture::Target target = texture->target();
+
+ texture->bind();
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces)
+ m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ m_extraFuncs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
+ texture->release();
+}
+
+void GraphicsHelperES3_2::setVerticesPerPatch(GLint verticesPerPatch)
+{
+ m_extraFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch);
+}
+
+void GraphicsHelperES3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex, GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
+
+ m_extraFuncs->glDrawElementsInstancedBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances,
+ baseVertex);
+}
+
+UniformType GraphicsHelperES3_2::uniformTypeFromGLType(GLenum glType)
+{
+ switch (glType) {
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ return UniformType::Image;
+
+ default:
+ return GraphicsHelperES3_1::uniformTypeFromGLType(glType);
+ }
+}
+
+uint GraphicsHelperES3_2::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+
+ switch (description.m_type) {
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ rawByteSize = 4;
+ break;
+
+ default:
+ rawByteSize = GraphicsHelperES3_1::uniformByteSize(description);
+ break;
+ }
+
+ return rawByteSize;
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h
new file mode 100644
index 000000000..9552e656a
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_2_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERES3_2_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERES3_2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperes3_1_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsHelperES3_2 : public GraphicsHelperES3_1
+{
+public:
+ GraphicsHelperES3_2();
+ ~GraphicsHelperES3_2();
+
+ bool supportsFeature(Feature feature) const override;
+
+ // QGraphicHelperInterface interface
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERES3_2_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_p.h
new file mode 100644
index 000000000..c985ba24a
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperes3_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** Copyright (C) 2016 Svenn-Arne Dragly.
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERES3_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERES3_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperes2_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsHelperES3 : public GraphicsHelperES2
+{
+public:
+ GraphicsHelperES3();
+ ~GraphicsHelperES3();
+
+ // QGraphicHelperInterface interface
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ bool supportsFeature(Feature feature) const override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+protected:
+ QOpenGLExtraFunctions *m_extraFuncs = nullptr;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERES3_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
new file mode 100644
index 000000000..3afc29d2f
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2.cpp
@@ -0,0 +1,935 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "graphicshelpergl2_p.h"
+#ifndef QT_OPENGL_ES_2
+#include <QOpenGLFunctions_2_0>
+#include <private/attachmentpack_p.h>
+#include <QtOpenGLExtensions/QOpenGLExtensions>
+#include <qgraphicsutils_p.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperGL2::GraphicsHelperGL2()
+ : m_funcs(nullptr)
+ , m_fboFuncs(nullptr)
+{
+
+}
+
+void GraphicsHelperGL2::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *functions)
+{
+ Q_UNUSED(context);
+ m_funcs = static_cast<QOpenGLFunctions_2_0*>(functions);
+ const bool ok = m_funcs->initializeOpenGLFunctions();
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+ if (context->hasExtension(QByteArrayLiteral("GL_ARB_framebuffer_object"))) {
+ m_fboFuncs = new QOpenGLExtension_ARB_framebuffer_object();
+ const bool extensionOk = m_fboFuncs->initializeOpenGLFunctions();
+ Q_ASSERT(extensionOk);
+ Q_UNUSED(extensionOk);
+ }
+}
+
+void GraphicsHelperGL2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
+
+ if (baseVertex != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertex is not supported with OpenGL ES 2";
+
+ for (GLint i = 0; i < instances; i++)
+ drawElements(primitiveType,
+ primitiveCount,
+ indexType,
+ indices);
+}
+
+void GraphicsHelperGL2::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ for (GLint i = 0; i < instances; i++)
+ drawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL2::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL 2";
+ for (GLint i = 0; i < instances; i++)
+ drawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL2::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ if (baseVertex != 0)
+ qWarning() << "glDrawElementsBaseVertex is not supported with OpenGL 2";
+
+ m_funcs->glDrawElements(primitiveType,
+ primitiveCount,
+ indexType,
+ indices);
+}
+
+void GraphicsHelperGL2::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_funcs->glDrawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL2::drawElementsIndirect(GLenum, GLenum, void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 2";
+}
+
+void GraphicsHelperGL2::drawArraysIndirect(GLenum , void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 2";
+}
+
+void GraphicsHelperGL2::setVerticesPerPatch(GLint verticesPerPatch)
+{
+ Q_UNUSED(verticesPerPatch);
+ qWarning() << "Tessellation not supported with OpenGL 2";
+}
+
+void GraphicsHelperGL2::useProgram(GLuint programId)
+{
+ m_funcs->glUseProgram(programId);
+}
+
+QVector<ShaderUniform> GraphicsHelperGL2::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ }
+ return uniforms;
+}
+
+QVector<ShaderAttribute> GraphicsHelperGL2::programAttributesAndLocations(GLuint programId)
+{
+ QVector<ShaderAttribute> attributes;
+ GLint nbrActiveAttributes = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
+ for (GLint i = 0; i < nbrActiveAttributes; i++) {
+ ShaderAttribute attribute;
+ GLsizei attributeNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
+ attributes.append(attribute);
+ }
+ return attributes;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperGL2::programUniformBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ QVector<ShaderUniformBlock> blocks;
+ qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
+ return blocks;
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperGL2::programShaderStorageBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ qWarning() << "SSBO are not supported by OpenGL 2.0 (since OpenGL 4.3)";
+ return QVector<ShaderStorageBlock>();
+}
+
+void GraphicsHelperGL2::vertexAttribDivisor(GLuint index,
+ GLuint divisor)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
+}
+
+void GraphicsHelperGL2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL2::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL2::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
+void *GraphicsHelperGL2::fenceSync()
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+ return nullptr;
+}
+
+void GraphicsHelperGL2::clientWaitSync(void *, GLuint64 )
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
+void GraphicsHelperGL2::waitSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
+bool GraphicsHelperGL2::wasSyncSignaled(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+ return false;
+}
+
+void GraphicsHelperGL2::deleteSync(void *)
+{
+ qWarning() << "Fences are not supported by OpenGL 2.0 (since OpenGL 3.2)";
+}
+
+void GraphicsHelperGL2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
+void GraphicsHelperGL2::blendEquation(GLenum mode)
+{
+ m_funcs->glBlendEquation(mode);
+}
+
+void GraphicsHelperGL2::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sfactor);
+ Q_UNUSED(dfactor);
+
+ qWarning() << "glBlendFunci() not supported by OpenGL 2.0 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL2::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sRGB);
+ Q_UNUSED(dRGB);
+ Q_UNUSED(sAlpha);
+ Q_UNUSED(dAlpha);
+
+ qWarning() << "glBlendFuncSeparatei() not supported by OpenGL 2.0 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL2::alphaTest(GLenum mode1, GLenum mode2)
+{
+ m_funcs->glEnable(GL_ALPHA_TEST);
+ m_funcs->glAlphaFunc(mode1, mode2);
+}
+
+void GraphicsHelperGL2::depthTest(GLenum mode)
+{
+ m_funcs->glEnable(GL_DEPTH_TEST);
+ m_funcs->glDepthFunc(mode);
+}
+
+void GraphicsHelperGL2::depthMask(GLenum mode)
+{
+ m_funcs->glDepthMask(mode);
+}
+
+void GraphicsHelperGL2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
+void GraphicsHelperGL2::frontFace(GLenum mode)
+{
+ m_funcs->glFrontFace(mode);
+}
+
+void GraphicsHelperGL2::setMSAAEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_MULTISAMPLE)
+ : m_funcs->glDisable(GL_MULTISAMPLE);
+}
+
+void GraphicsHelperGL2::setAlphaCoverageEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
+ : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+}
+
+GLuint GraphicsHelperGL2::createFrameBufferObject()
+{
+ if (m_fboFuncs != nullptr) {
+ GLuint id;
+ m_fboFuncs->glGenFramebuffers(1, &id);
+ return id;
+ }
+ qWarning() << "FBO not supported by your OpenGL hardware";
+ return 0;
+}
+
+void GraphicsHelperGL2::releaseFrameBufferObject(GLuint frameBufferId)
+{
+ if (m_fboFuncs != nullptr)
+ m_fboFuncs->glDeleteFramebuffers(1, &frameBufferId);
+ else
+ qWarning() << "FBO not supported by your OpenGL hardware";
+}
+
+bool GraphicsHelperGL2::checkFrameBufferComplete()
+{
+ if (m_fboFuncs != nullptr)
+ return (m_fboFuncs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+ return false;
+}
+
+bool GraphicsHelperGL2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
+void GraphicsHelperGL2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ if (m_fboFuncs != nullptr) {
+ GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+ else
+ qCritical() << "DepthStencil Attachment not supported on OpenGL 2.0";
+
+ const QOpenGLTexture::Target target = texture->target();
+
+ if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face == QAbstractTexture::AllFaces) {
+ qWarning() << "OpenGL 2.0 doesn't handle attaching all the faces of a cube map texture at once to an FBO";
+ return;
+ }
+
+ texture->bind();
+ if (target == QOpenGLTexture::Target3D)
+ m_fboFuncs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMap)
+ m_fboFuncs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else if (target == QOpenGLTexture::Target1D)
+ m_fboFuncs->glFramebufferTexture1D(GL_DRAW_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
+ else if (target == QOpenGLTexture::Target2D || target == QOpenGLTexture::TargetRectangle)
+ m_fboFuncs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, target, texture->textureId(), attachment.m_mipLevel);
+ else
+ qCritical() << "Texture format not supported for Attachment on OpenGL 2.0";
+ texture->release();
+ }
+}
+
+void GraphicsHelperGL2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
+bool GraphicsHelperGL2::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case MRT:
+ return (m_fboFuncs != nullptr);
+ case TextureDimensionRetrieval:
+ case MapBuffer:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperGL2::drawBuffers(GLsizei n, const int *bufs)
+{
+ QVarLengthArray<GLenum, 16> drawBufs(n);
+
+ for (int i = 0; i < n; i++)
+ drawBufs[i] = GL_COLOR_ATTACHMENT0 + bufs[i];
+ m_funcs->glDrawBuffers(n, drawBufs.constData());
+}
+
+void GraphicsHelperGL2::bindFragDataLocation(GLuint, const QHash<QString, int> &)
+{
+ qCritical() << "bindFragDataLocation is not supported by GL 2.0";
+}
+
+void GraphicsHelperGL2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode)
+{
+ if (m_fboFuncs != nullptr) {
+ switch (mode) {
+ case FBODraw:
+ m_fboFuncs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBORead:
+ m_fboFuncs->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBOReadAndDraw:
+ default:
+ m_fboFuncs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+ return;
+ }
+ } else {
+ qWarning() << "FBO not supported by your OpenGL hardware";
+ }
+}
+
+void GraphicsHelperGL2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 2.0 (since OpenGL 4.2)";
+
+}
+
+GLuint GraphicsHelperGL2::boundFrameBufferObject()
+{
+ GLint id = 0;
+ m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id);
+ return id;
+}
+
+void GraphicsHelperGL2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(uniformBlockIndex);
+ Q_UNUSED(uniformBlockBinding);
+ qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
+}
+
+void GraphicsHelperGL2::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(shaderStorageBlockIndex);
+ Q_UNUSED(shaderStorageBlockBinding);
+ qWarning() << "SSBO are not supported by OpenGL 2.0 (since OpenGL 4.3)";
+}
+
+void GraphicsHelperGL2::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ Q_UNUSED(target);
+ Q_UNUSED(index);
+ Q_UNUSED(buffer);
+ qWarning() << "bindBufferBase is not supported by OpenGL 2.0 (since OpenGL 3.0)";
+}
+
+void GraphicsHelperGL2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ Q_UNUSED(v);
+ Q_UNUSED(description);
+ Q_UNUSED(buffer);
+ qWarning() << "UBO are not supported by OpenGL 2.0 (since OpenGL 3.1)";
+}
+
+uint GraphicsHelperGL2::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT2x4:
+ rawByteSize = matrixStride ? 2 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT4x2:
+ rawByteSize = matrixStride ? 4 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT2x3:
+ rawByteSize = matrixStride ? 2 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT3x2:
+ rawByteSize = matrixStride ? 3 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_FLOAT_MAT4x3:
+ rawByteSize = matrixStride ? 4 * matrixStride : 48;
+ break;
+
+ case GL_FLOAT_MAT3x4:
+ rawByteSize = matrixStride ? 3 * matrixStride : 48;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ rawByteSize = 4;
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void GraphicsHelperGL2::enableClipPlane(int clipPlane)
+{
+ m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL2::disableClipPlane(int clipPlane)
+{
+ m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL2::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
+{
+ double plane[4];
+ plane[0] = normal.x();
+ plane[1] = normal.y();
+ plane[2] = normal.z();
+ plane[3] = distance;
+
+ m_funcs->glClipPlane(GL_CLIP_PLANE0 + clipPlane, plane);
+}
+
+GLint GraphicsHelperGL2::maxClipPlaneCount()
+{
+ GLint max = 0;
+ m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max);
+ return max;
+}
+
+void GraphicsHelperGL2::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ Q_UNUSED(barriers);
+ qWarning() << "memory barrier is not supported by OpenGL 2.0 (since 4.3)";
+}
+
+void GraphicsHelperGL2::enablePrimitiveRestart(int)
+{
+}
+
+void GraphicsHelperGL2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
+void GraphicsHelperGL2::disablePrimitiveRestart()
+{
+}
+
+void GraphicsHelperGL2::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ Q_UNUSED(drawbuffer);
+ Q_UNUSED(values);
+ qWarning() << "glClearBuffer*() not supported by OpenGL 2.0";
+}
+
+void GraphicsHelperGL2::pointSize(bool programmable, GLfloat value)
+{
+ m_funcs->glEnable(GL_POINT_SPRITE);
+ if (programmable)
+ m_funcs->glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ else
+ m_funcs->glPointSize(value);
+}
+
+void GraphicsHelperGL2::enablei(GLenum cap, GLuint index)
+{
+ Q_UNUSED(cap);
+ Q_UNUSED(index);
+ qWarning() << "glEnablei() not supported by OpenGL 2.0 (since 3.0)";
+}
+
+void GraphicsHelperGL2::disablei(GLenum cap, GLuint index)
+{
+ Q_UNUSED(cap);
+ Q_UNUSED(index);
+ qWarning() << "glDisablei() not supported by OpenGL 2.0 (since 3.0)";
+}
+
+void GraphicsHelperGL2::setSeamlessCubemap(bool enable)
+{
+ Q_UNUSED(enable);
+ qWarning() << "GL_TEXTURE_CUBE_MAP_SEAMLESS not supported by OpenGL 2.0 (since 3.2)";
+}
+
+QSize GraphicsHelperGL2::getRenderBufferDimensions(GLuint renderBufferId)
+{
+ Q_UNUSED(renderBufferId);
+ qCritical() << "RenderBuffer dimensions retrival not supported on OpenGL 2.0";
+ return QSize(0,0);
+}
+
+QSize GraphicsHelperGL2::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindTexture(target, textureId);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ m_funcs->glBindTexture(target, 0);
+
+ return QSize(width, height);
+}
+
+void GraphicsHelperGL2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ Q_UNUSED(wx);
+ Q_UNUSED(wy);
+ Q_UNUSED(wz);
+ qWarning() << "Compute Shaders are not supported by OpenGL 2.0 (since OpenGL 4.3)";
+}
+
+char *GraphicsHelperGL2::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ Q_UNUSED(size);
+ return static_cast<char*>(m_funcs->glMapBuffer(target, GL_READ_WRITE));
+}
+
+GLboolean GraphicsHelperGL2::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
+void GraphicsHelperGL2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform1fv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform2fv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform3fv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform4fv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform1iv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform2iv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform3iv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform4iv(location, count, values);
+}
+
+void GraphicsHelperGL2::glUniform1uiv(GLint , GLsizei , const GLuint *)
+{
+ qWarning() << "glUniform1uiv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniform2uiv(GLint , GLsizei , const GLuint *)
+{
+ qWarning() << "glUniform2uiv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniform3uiv(GLint , GLsizei , const GLuint *)
+{
+ qWarning() << "glUniform3uiv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniform4uiv(GLint , GLsizei , const GLuint *)
+{
+ qWarning() << "glUniform4uiv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL2::glUniformMatrix2x3fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix2x3fv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix3x2fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix3x2fv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix2x4fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix2x4fv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix4x2fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix4x2fv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix3x4fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix3x4fv not supported by GL 2";
+}
+
+void GraphicsHelperGL2::glUniformMatrix4x3fv(GLint , GLsizei , const GLfloat *)
+{
+ qWarning() << "glUniformMatrix4x3fv not supported by GL 2";
+}
+
+UniformType GraphicsHelperGL2::uniformTypeFromGLType(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ return UniformType::Float;
+ case GL_FLOAT_VEC2:
+ return UniformType::Vec2;
+ case GL_FLOAT_VEC3:
+ return UniformType::Vec3;
+ case GL_FLOAT_VEC4:
+ return UniformType::Vec4;
+ case GL_FLOAT_MAT2:
+ return UniformType::Mat2;
+ case GL_FLOAT_MAT3:
+ return UniformType::Mat3;
+ case GL_FLOAT_MAT4:
+ return UniformType::Mat4;
+ case GL_INT:
+ return UniformType::Int;
+ case GL_INT_VEC2:
+ return UniformType::IVec2;
+ case GL_INT_VEC3:
+ return UniformType::IVec3;
+ case GL_INT_VEC4:
+ return UniformType::IVec4;
+ case GL_BOOL:
+ return UniformType::Bool;
+ case GL_BOOL_VEC2:
+ return UniformType::BVec2;
+ case GL_BOOL_VEC3:
+ return UniformType::BVec3;
+ case GL_BOOL_VEC4:
+ return UniformType::BVec4;
+
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_3D:
+ return UniformType::Sampler;
+
+ default:
+ Q_UNREACHABLE();
+ return UniformType::Float;
+ }
+}
+
+void GraphicsHelperGL2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ Q_UNUSED(srcX0);
+ Q_UNUSED(srcX1);
+ Q_UNUSED(srcY0);
+ Q_UNUSED(srcY1);
+ Q_UNUSED(dstX0);
+ Q_UNUSED(dstX1);
+ Q_UNUSED(dstY0);
+ Q_UNUSED(dstY1);
+ Q_UNUSED(mask);
+ Q_UNUSED(filter);
+ qWarning() << "Framebuffer blits are not supported by ES 2.0 (since ES 3.1)";
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
new file mode 100644
index 000000000..35391471f
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl2_p.h
@@ -0,0 +1,183 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERGL2_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERGL2_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperinterface_p.h>
+
+#ifndef QT_OPENGL_ES_2
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLFunctions_2_0;
+class QOpenGLExtension_ARB_framebuffer_object;
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT GraphicsHelperGL2 : public GraphicsHelperInterface
+{
+public:
+ GraphicsHelperGL2();
+
+ // QGraphicHelperInterface interface
+ void alphaTest(GLenum mode1, GLenum mode2) override;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blendEquation(GLenum mode) override;
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ GLuint boundFrameBufferObject() override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ bool checkFrameBufferComplete() override;
+ void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
+ GLuint createFrameBufferObject() override;
+ void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
+ void depthTest(GLenum mode) override;
+ void disableClipPlane(int clipPlane) override;
+ void disablei(GLenum cap, GLuint index) override;
+ void disablePrimitiveRestart() override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLint baseVertex = 0) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void enableClipPlane(int clipPlane) override;
+ void enablei(GLenum cap, GLuint index) override;
+ void enablePrimitiveRestart(int primitiveRestartIndex) override;
+ void enableVertexAttributeArray(int location) override;
+ void frontFace(GLenum mode) override;
+ QSize getRenderBufferDimensions(GLuint renderBufferId) override;
+ QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ void pointSize(bool programmable, GLfloat value) override;
+ GLint maxClipPlaneCount() override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+ void releaseFrameBufferObject(GLuint frameBufferId) override;
+ void setMSAAEnabled(bool enable) override;
+ void setAlphaCoverageEnabled(bool enable) override;
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance) override;
+ void setSeamlessCubemap(bool enable) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ bool supportsFeature(Feature feature) const override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void useProgram(GLuint programId) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ void glUniform1iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform2iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform3iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform4iv(GLint location, GLsizei count, const GLint *value) override;
+
+ void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) override;
+
+ void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+
+private:
+ QOpenGLFunctions_2_0 *m_funcs;
+ QOpenGLExtension_ARB_framebuffer_object *m_fboFuncs;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERGL2_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
new file mode 100644
index 000000000..17850cf00
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2.cpp
@@ -0,0 +1,1245 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "graphicshelpergl3_2_p.h"
+
+#ifndef QT_OPENGL_ES_2
+#include <QOpenGLFunctions_3_2_Core>
+#include <QOpenGLFunctions_3_3_Core>
+#include <QtOpenGLExtensions/qopenglextensions.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <private/attachmentpack_p.h>
+#include <qgraphicsutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+# ifndef QT_OPENGL_3
+# define GL_PATCH_VERTICES 36466
+# define GL_ACTIVE_RESOURCES 0x92F5
+# define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+# define GL_BUFFER_BINDING 0x9302
+# define GL_BUFFER_DATA_SIZE 0x9303
+# define GL_NUM_ACTIVE_VARIABLES 0x9304
+# define GL_SHADER_STORAGE_BLOCK 0x92E6
+# define GL_UNIFORM 0x92E1
+# define GL_UNIFORM_BLOCK 0x92E2
+# define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+# define GL_UNIFORM_OFFSET 0x8A3B
+# define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+# define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+# define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+# define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+# define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+# endif
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperGL3_2::GraphicsHelperGL3_2()
+ : m_funcs(nullptr)
+ , m_tessFuncs()
+{
+}
+
+GraphicsHelperGL3_2::~GraphicsHelperGL3_2()
+{
+}
+
+void GraphicsHelperGL3_2::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *functions)
+{
+ m_funcs = static_cast<QOpenGLFunctions_3_2_Core*>(functions);
+ const bool ok = m_funcs->initializeOpenGLFunctions();
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+
+ if (context->hasExtension(QByteArrayLiteral("GL_ARB_tessellation_shader"))) {
+ m_tessFuncs.reset(new QOpenGLExtension_ARB_tessellation_shader);
+ m_tessFuncs->initializeOpenGLFunctions();
+ }
+}
+
+void GraphicsHelperGL3_2::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
+
+ // glDrawElements OpenGL 3.1 or greater
+ m_funcs->glDrawElementsInstancedBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances,
+ baseVertex);
+}
+
+void GraphicsHelperGL3_2::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ // glDrawArraysInstanced OpenGL 3.1 or greater
+ m_funcs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperGL3_2::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL 3";
+ m_funcs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperGL3_2::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ m_funcs->glDrawElementsBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ baseVertex);
+}
+
+void GraphicsHelperGL3_2::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_funcs->glDrawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL3_2::drawElementsIndirect(GLenum, GLenum, void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 3.2";
+}
+
+void GraphicsHelperGL3_2::drawArraysIndirect(GLenum , void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 3.2";
+}
+
+void GraphicsHelperGL3_2::setVerticesPerPatch(GLint verticesPerPatch)
+{
+#if defined(QT_OPENGL_4)
+ if (!m_tessFuncs) {
+ qWarning() << "Tessellation not supported with OpenGL 3 without GL_ARB_tessellation_shader";
+ return;
+ }
+
+ m_tessFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch);
+#else
+ Q_UNUSED(verticesPerPatch);
+ qWarning() << "Tessellation not supported";
+#endif
+}
+
+void GraphicsHelperGL3_2::useProgram(GLuint programId)
+{
+ m_funcs->glUseProgram(programId);
+}
+
+QVector<ShaderUniform> GraphicsHelperGL3_2::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_MATRIX_STRIDE, &uniform.m_matrixStride);
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ qCDebug(Render::Rendering) << uniform.m_name << "size" << uniform.m_size
+ << " offset" << uniform.m_offset
+ << " rawSize" << uniform.m_rawByteSize;
+ }
+
+ return uniforms;
+}
+
+QVector<ShaderAttribute> GraphicsHelperGL3_2::programAttributesAndLocations(GLuint programId)
+{
+ QVector<ShaderAttribute> attributes;
+ GLint nbrActiveAttributes = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
+ for (GLint i = 0; i < nbrActiveAttributes; i++) {
+ ShaderAttribute attribute;
+ GLsizei attributeNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
+ attributes.append(attribute);
+ }
+ return attributes;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperGL3_2::programUniformBlocks(GLuint programId)
+{
+ QVector<ShaderUniformBlock> blocks;
+ GLint nbrActiveUniformsBlocks = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORM_BLOCKS, &nbrActiveUniformsBlocks);
+ blocks.reserve(nbrActiveUniformsBlocks);
+ for (GLint i = 0; i < nbrActiveUniformsBlocks; i++) {
+ QByteArray uniformBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderUniformBlock uniformBlock;
+ m_funcs->glGetActiveUniformBlockName(programId, i, 256, &length, uniformBlockName.data());
+ uniformBlock.m_name = QString::fromUtf8(uniformBlockName.left(length));
+ uniformBlock.m_index = i;
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &uniformBlock.m_activeUniformsCount);
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_BINDING, &uniformBlock.m_binding);
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlock.m_size);
+ blocks.append(uniformBlock);
+ }
+ return blocks;
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperGL3_2::programShaderStorageBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ QVector<ShaderStorageBlock> blocks;
+ qWarning() << "SSBO are not supported by OpenGL 3.2 (since OpenGL 4.3)";
+ return blocks;
+}
+
+void GraphicsHelperGL3_2::vertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ Q_UNUSED(index);
+ Q_UNUSED(divisor);
+ qCWarning(Render::Rendering) << "Vertex attribute divisor not available with OpenGL 3.2 core";
+}
+
+void GraphicsHelperGL3_2::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL3_2::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL3_2::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
+void *GraphicsHelperGL3_2::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL3_2::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperGL3_2::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL3_2::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL3_2::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
+void GraphicsHelperGL3_2::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
+void GraphicsHelperGL3_2::blendEquation(GLenum mode)
+{
+ m_funcs->glBlendEquation(mode);
+}
+
+void GraphicsHelperGL3_2::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sfactor);
+ Q_UNUSED(dfactor);
+
+ qWarning() << "glBlendFunci() not supported by OpenGL 3.0 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL3_2::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sRGB);
+ Q_UNUSED(dRGB);
+ Q_UNUSED(sAlpha);
+ Q_UNUSED(dAlpha);
+
+ qWarning() << "glBlendFuncSeparatei() not supported by OpenGL 3.0 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL3_2::alphaTest(GLenum, GLenum)
+{
+ qCWarning(Render::Rendering) << "AlphaTest not available with OpenGL 3.2 core";
+}
+
+void GraphicsHelperGL3_2::depthTest(GLenum mode)
+{
+ m_funcs->glEnable(GL_DEPTH_TEST);
+ m_funcs->glDepthFunc(mode);
+}
+
+void GraphicsHelperGL3_2::depthMask(GLenum mode)
+{
+ m_funcs->glDepthMask(mode);
+}
+
+void GraphicsHelperGL3_2::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
+void GraphicsHelperGL3_2::frontFace(GLenum mode)
+{
+ m_funcs->glFrontFace(mode);
+
+}
+
+void GraphicsHelperGL3_2::setMSAAEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_MULTISAMPLE)
+ : m_funcs->glDisable(GL_MULTISAMPLE);
+}
+
+void GraphicsHelperGL3_2::setAlphaCoverageEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
+ : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+}
+
+GLuint GraphicsHelperGL3_2::createFrameBufferObject()
+{
+ GLuint id;
+ m_funcs->glGenFramebuffers(1, &id);
+ return id;
+}
+
+void GraphicsHelperGL3_2::releaseFrameBufferObject(GLuint frameBufferId)
+{
+ m_funcs->glDeleteFramebuffers(1, &frameBufferId);
+}
+
+void GraphicsHelperGL3_2::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode)
+{
+ switch (mode) {
+ case FBODraw:
+ m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBORead:
+ m_funcs->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBOReadAndDraw:
+ default:
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+ return;
+ }
+}
+
+void GraphicsHelperGL3_2::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 3.2 (since OpenGL 4.2)";
+
+}
+
+GLuint GraphicsHelperGL3_2::boundFrameBufferObject()
+{
+ GLint id = 0;
+ m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id);
+ return id;
+}
+
+bool GraphicsHelperGL3_2::checkFrameBufferComplete()
+{
+ return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+bool GraphicsHelperGL3_2::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
+void GraphicsHelperGL3_2::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+
+ texture->bind();
+ QOpenGLTexture::Target target = texture->target();
+ if (target == QOpenGLTexture::Target1DArray || target == QOpenGLTexture::Target2DArray ||
+ target == QOpenGLTexture::Target2DMultisampleArray || target == QOpenGLTexture::Target3D)
+ m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMapArray)
+ m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMap)
+ m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
+ texture->release();
+}
+
+void GraphicsHelperGL3_2::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
+bool GraphicsHelperGL3_2::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case MRT:
+ case UniformBufferObject:
+ case PrimitiveRestart:
+ case RenderBufferDimensionRetrieval:
+ case TextureDimensionRetrieval:
+ case BindableFragmentOutputs:
+ case BlitFramebuffer:
+ case Fences:
+ return true;
+ case Tessellation:
+ return !m_tessFuncs.isNull();
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperGL3_2::drawBuffers(GLsizei n, const int *bufs)
+{
+ // Use QVarLengthArray here
+ QVarLengthArray<GLenum, 16> drawBufs(n);
+
+ for (int i = 0; i < n; i++)
+ drawBufs[i] = GL_COLOR_ATTACHMENT0 + bufs[i];
+ m_funcs->glDrawBuffers(n, drawBufs.constData());
+}
+
+void GraphicsHelperGL3_2::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs)
+{
+ for (auto it = outputs.begin(), end = outputs.end(); it != end; ++it)
+ m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str());
+}
+
+void GraphicsHelperGL3_2::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsHelperGL3_2::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(shaderStorageBlockIndex);
+ Q_UNUSED(shaderStorageBlockBinding);
+ qWarning() << "SSBO are not supported by OpenGL 3.0 (since OpenGL 4.3)";
+}
+
+void GraphicsHelperGL3_2::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ m_funcs->glBindBufferBase(target, index, buffer);
+}
+
+void GraphicsHelperGL3_2::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+
+ case GL_FLOAT: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_FLOAT_VEC2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_FLOAT_VEC3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_FLOAT_VEC4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 3);
+ break;
+ }
+
+ case GL_INT: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_INT_VEC2: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_INT_VEC3: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_INT_VEC4: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_UNSIGNED_INT: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC2: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC3: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC4: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_BOOL: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_BOOL_VEC2: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_BOOL_VEC3: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_BOOL_VEC4: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name;
+ break;
+ }
+}
+
+uint GraphicsHelperGL3_2::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT2x4:
+ rawByteSize = matrixStride ? 2 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT4x2:
+ rawByteSize = matrixStride ? 4 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT2x3:
+ rawByteSize = matrixStride ? 2 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT3x2:
+ rawByteSize = matrixStride ? 3 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_FLOAT_MAT4x3:
+ rawByteSize = matrixStride ? 4 * matrixStride : 48;
+ break;
+
+ case GL_FLOAT_MAT3x4:
+ rawByteSize = matrixStride ? 3 * matrixStride : 48;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_UNSIGNED_INT:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ rawByteSize = 4;
+ break;
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void GraphicsHelperGL3_2::enableClipPlane(int clipPlane)
+{
+ m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL3_2::disableClipPlane(int clipPlane)
+{
+ m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL3_2::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
+{
+ // deprecated
+ Q_UNUSED(clipPlane);
+ Q_UNUSED(normal);
+ Q_UNUSED(distance);
+}
+
+GLint GraphicsHelperGL3_2::maxClipPlaneCount()
+{
+ GLint max = 0;
+ m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max);
+ return max;
+}
+
+void GraphicsHelperGL3_2::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ Q_UNUSED(barriers);
+ qWarning() << "memory barrier is not supported by OpenGL 3.0 (since 4.3)";
+}
+
+void GraphicsHelperGL3_2::enablePrimitiveRestart(int primitiveRestartIndex)
+{
+ m_funcs->glPrimitiveRestartIndex(primitiveRestartIndex);
+ m_funcs->glEnable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL3_2::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
+void GraphicsHelperGL3_2::disablePrimitiveRestart()
+{
+ m_funcs->glDisable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL3_2::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ GLfloat vec[4] = {values[0], values[1], values[2], values[3]};
+ m_funcs->glClearBufferfv(GL_COLOR, drawbuffer, vec);
+}
+
+void GraphicsHelperGL3_2::pointSize(bool programmable, GLfloat value)
+{
+ if (programmable) {
+ m_funcs->glEnable(GL_PROGRAM_POINT_SIZE);
+ } else {
+ m_funcs->glDisable(GL_PROGRAM_POINT_SIZE);
+ m_funcs->glPointSize(value);
+ }
+}
+
+void GraphicsHelperGL3_2::enablei(GLenum cap, GLuint index)
+{
+ m_funcs->glEnablei(cap, index);
+}
+
+void GraphicsHelperGL3_2::disablei(GLenum cap, GLuint index)
+{
+ m_funcs->glDisablei(cap, index);
+}
+
+void GraphicsHelperGL3_2::setSeamlessCubemap(bool enable)
+{
+ if (enable)
+ m_funcs->glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ else
+ m_funcs->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+}
+
+QSize GraphicsHelperGL3_2::getRenderBufferDimensions(GLuint renderBufferId)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ return QSize(width, height);
+}
+
+QSize GraphicsHelperGL3_2::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindTexture(target, textureId);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ m_funcs->glBindTexture(target, 0);
+
+ return QSize(width, height);
+}
+
+void GraphicsHelperGL3_2::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ Q_UNUSED(wx);
+ Q_UNUSED(wy);
+ Q_UNUSED(wz);
+ qWarning() << "Compute Shaders are not supported by OpenGL 3.2 (since OpenGL 4.3)";
+}
+
+char *GraphicsHelperGL3_2::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+}
+
+GLboolean GraphicsHelperGL3_2::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
+void GraphicsHelperGL3_2::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform1fv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform2fv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform3fv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform4fv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform1iv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform2iv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform3iv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform4iv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform1uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform1uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform2uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform2uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform3uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform3uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniform4uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform4uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_2::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x3fv(location, count, false, values);
+}
+
+UniformType GraphicsHelperGL3_2::uniformTypeFromGLType(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ return UniformType::Float;
+ case GL_FLOAT_VEC2:
+ return UniformType::Vec2;
+ case GL_FLOAT_VEC3:
+ return UniformType::Vec3;
+ case GL_FLOAT_VEC4:
+ return UniformType::Vec4;
+ case GL_FLOAT_MAT2:
+ return UniformType::Mat2;
+ case GL_FLOAT_MAT3:
+ return UniformType::Mat3;
+ case GL_FLOAT_MAT4:
+ return UniformType::Mat4;
+ case GL_FLOAT_MAT2x3:
+ return UniformType::Mat2x3;
+ case GL_FLOAT_MAT3x2:
+ return UniformType::Mat3x2;
+ case GL_FLOAT_MAT2x4:
+ return UniformType::Mat2x4;
+ case GL_FLOAT_MAT4x2:
+ return UniformType::Mat4x2;
+ case GL_FLOAT_MAT3x4:
+ return UniformType::Mat3x4;
+ case GL_FLOAT_MAT4x3:
+ return UniformType::Mat4x3;
+ case GL_INT:
+ return UniformType::Int;
+ case GL_INT_VEC2:
+ return UniformType::IVec2;
+ case GL_INT_VEC3:
+ return UniformType::IVec3;
+ case GL_INT_VEC4:
+ return UniformType::IVec4;
+ case GL_UNSIGNED_INT:
+ return UniformType::UInt;
+ case GL_UNSIGNED_INT_VEC2:
+ return UniformType::UIVec2;
+ case GL_UNSIGNED_INT_VEC3:
+ return UniformType::UIVec3;
+ case GL_UNSIGNED_INT_VEC4:
+ return UniformType::UIVec4;
+ case GL_BOOL:
+ return UniformType::Bool;
+ case GL_BOOL_VEC2:
+ return UniformType::BVec2;
+ case GL_BOOL_VEC3:
+ return UniformType::BVec3;
+ case GL_BOOL_VEC4:
+ return UniformType::BVec4;
+
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_2D_RECT:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_SAMPLER_3D:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ return UniformType::Sampler;
+ default:
+ Q_UNREACHABLE();
+ return UniformType::Float;
+ }
+}
+
+void GraphicsHelperGL3_2::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
new file mode 100644
index 000000000..b6b2f7141
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_2_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERGL3_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERGL3_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperinterface_p.h>
+#include <QtCore/qscopedpointer.h>
+
+#ifndef QT_OPENGL_ES_2
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLFunctions_3_2_Core;
+class QOpenGLExtension_ARB_tessellation_shader;
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT GraphicsHelperGL3_2 : public GraphicsHelperInterface
+{
+public:
+ GraphicsHelperGL3_2();
+ ~GraphicsHelperGL3_2();
+
+ // QGraphicHelperInterface interface
+ void alphaTest(GLenum mode1, GLenum mode2) override;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blendEquation(GLenum mode) override;
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ GLuint boundFrameBufferObject() override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ bool checkFrameBufferComplete() override;
+ void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
+ GLuint createFrameBufferObject() override;
+ void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
+ void depthTest(GLenum mode) override;
+ void disableClipPlane(int clipPlane) override;
+ void disablei(GLenum cap, GLuint index) override;
+ void disablePrimitiveRestart() override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLint baseVertex = 0) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void enableClipPlane(int clipPlane) override;
+ void enablei(GLenum cap, GLuint index) override;
+ void enablePrimitiveRestart(int primitiveRestartIndex) override;
+ void enableVertexAttributeArray(int location) override;
+ void frontFace(GLenum mode) override;
+ QSize getRenderBufferDimensions(GLuint renderBufferId) override;
+ QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ void pointSize(bool programmable, GLfloat value) override;
+ GLint maxClipPlaneCount() override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+ void releaseFrameBufferObject(GLuint frameBufferId) override;
+ void setMSAAEnabled(bool enable) override;
+ void setAlphaCoverageEnabled(bool enable) override;
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance) override;
+ void setSeamlessCubemap(bool enable) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ bool supportsFeature(Feature feature) const override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void useProgram(GLuint programId) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ void glUniform1iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform2iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform3iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform4iv(GLint location, GLsizei count, const GLint *value) override;
+
+ void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) override;
+
+ void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+
+private:
+ QOpenGLFunctions_3_2_Core *m_funcs;
+ QScopedPointer<QOpenGLExtension_ARB_tessellation_shader> m_tessFuncs;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERGL3_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
new file mode 100644
index 000000000..3d8e2acfc
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3.cpp
@@ -0,0 +1,1240 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "graphicshelpergl3_3_p.h"
+
+#ifndef QT_OPENGL_ES_2
+#include <QOpenGLFunctions_3_3_Core>
+#include <QtOpenGLExtensions/qopenglextensions.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <private/attachmentpack_p.h>
+#include <qgraphicsutils_p.h>
+
+# ifndef QT_OPENGL_3_2
+# define GL_PATCH_VERTICES 36466
+# define GL_ACTIVE_RESOURCES 0x92F5
+# define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+# define GL_BUFFER_BINDING 0x9302
+# define GL_BUFFER_DATA_SIZE 0x9303
+# define GL_NUM_ACTIVE_VARIABLES 0x9304
+# define GL_SHADER_STORAGE_BLOCK 0x92E6
+# define GL_UNIFORM 0x92E1
+# define GL_UNIFORM_BLOCK 0x92E2
+# define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+# define GL_UNIFORM_OFFSET 0x8A3B
+# define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+# define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+# define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+# define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+# define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+# endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+GraphicsHelperGL3_3::GraphicsHelperGL3_3()
+ : m_funcs(nullptr)
+ , m_tessFuncs()
+{
+}
+
+GraphicsHelperGL3_3::~GraphicsHelperGL3_3()
+{
+}
+
+void GraphicsHelperGL3_3::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *functions)
+{
+ m_funcs = static_cast<QOpenGLFunctions_3_3_Core*>(functions);
+ const bool ok = m_funcs->initializeOpenGLFunctions();
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+
+ if (context->hasExtension(QByteArrayLiteral("GL_ARB_tessellation_shader"))) {
+ m_tessFuncs.reset(new QOpenGLExtension_ARB_tessellation_shader);
+ m_tessFuncs->initializeOpenGLFunctions();
+ }
+}
+
+void GraphicsHelperGL3_3::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL 3";
+
+ // glDrawElements OpenGL 3.1 or greater
+ m_funcs->glDrawElementsInstancedBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances,
+ baseVertex);
+}
+
+void GraphicsHelperGL3_3::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ // glDrawArraysInstanced OpenGL 3.1 or greater
+ m_funcs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperGL3_3::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawArraysInstancedBaseInstance is not supported with OpenGL 3";
+ m_funcs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperGL3_3::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ m_funcs->glDrawElementsBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ baseVertex);
+}
+
+void GraphicsHelperGL3_3::drawElementsIndirect(GLenum, GLenum, void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 3";
+}
+
+void GraphicsHelperGL3_3::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_funcs->glDrawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL3_3::drawArraysIndirect(GLenum , void *)
+{
+ qWarning() << "Indirect Drawing is not supported with OpenGL 3";
+}
+
+void GraphicsHelperGL3_3::setVerticesPerPatch(GLint verticesPerPatch)
+{
+#if defined(QT_OPENGL_4)
+ if (!m_tessFuncs) {
+ qWarning() << "Tessellation not supported with OpenGL 3 without GL_ARB_tessellation_shader";
+ return;
+ }
+
+ m_tessFuncs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch);
+#else
+ Q_UNUSED(verticesPerPatch);
+ qWarning() << "Tessellation not supported";
+#endif
+}
+
+void GraphicsHelperGL3_3::useProgram(GLuint programId)
+{
+ m_funcs->glUseProgram(programId);
+}
+
+QVector<ShaderUniform> GraphicsHelperGL3_3::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORMS, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; i++) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_MATRIX_STRIDE, &uniform.m_matrixStride);
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ qCDebug(Render::Rendering) << uniform.m_name << "size" << uniform.m_size
+ << " offset" << uniform.m_offset
+ << " rawSize" << uniform.m_rawByteSize;
+ }
+
+ return uniforms;
+}
+
+QVector<ShaderAttribute> GraphicsHelperGL3_3::programAttributesAndLocations(GLuint programId)
+{
+ QVector<ShaderAttribute> attributes;
+ GLint nbrActiveAttributes = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
+ for (GLint i = 0; i < nbrActiveAttributes; i++) {
+ ShaderAttribute attribute;
+ GLsizei attributeNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
+ attributes.append(attribute);
+ }
+ return attributes;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperGL3_3::programUniformBlocks(GLuint programId)
+{
+ QVector<ShaderUniformBlock> blocks;
+ GLint nbrActiveUniformsBlocks = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_UNIFORM_BLOCKS, &nbrActiveUniformsBlocks);
+ blocks.reserve(nbrActiveUniformsBlocks);
+ for (GLint i = 0; i < nbrActiveUniformsBlocks; i++) {
+ QByteArray uniformBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderUniformBlock uniformBlock;
+ m_funcs->glGetActiveUniformBlockName(programId, i, 256, &length, uniformBlockName.data());
+ uniformBlock.m_name = QString::fromUtf8(uniformBlockName.left(length));
+ uniformBlock.m_index = i;
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &uniformBlock.m_activeUniformsCount);
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_BINDING, &uniformBlock.m_binding);
+ m_funcs->glGetActiveUniformBlockiv(programId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &uniformBlock.m_size);
+ blocks.append(uniformBlock);
+ }
+ return blocks;
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperGL3_3::programShaderStorageBlocks(GLuint programId)
+{
+ Q_UNUSED(programId);
+ QVector<ShaderStorageBlock> blocks;
+ qWarning() << "SSBO are not supported by OpenGL 3.3 (since OpenGL 4.3)";
+ return blocks;
+}
+
+void GraphicsHelperGL3_3::vertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ m_funcs->glVertexAttribDivisor(index, divisor);
+}
+
+void GraphicsHelperGL3_3::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ }
+}
+
+void GraphicsHelperGL3_3::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL3_3::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
+void *GraphicsHelperGL3_3::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL3_3::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+}
+
+void GraphicsHelperGL3_3::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL3_3::wasSyncSignaled(void *sync)
+{
+ GLint v;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL3_3::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
+void GraphicsHelperGL3_3::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
+void GraphicsHelperGL3_3::blendEquation(GLenum mode)
+{
+ m_funcs->glBlendEquation(mode);
+}
+
+void GraphicsHelperGL3_3::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sfactor);
+ Q_UNUSED(dfactor);
+
+ qWarning() << "glBlendFunci() not supported by OpenGL 3.3 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL3_3::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ Q_UNUSED(buf);
+ Q_UNUSED(sRGB);
+ Q_UNUSED(dRGB);
+ Q_UNUSED(sAlpha);
+ Q_UNUSED(dAlpha);
+
+ qWarning() << "glBlendFuncSeparatei() not supported by OpenGL 3.3 (since OpenGL 4.0)";
+}
+
+void GraphicsHelperGL3_3::alphaTest(GLenum, GLenum)
+{
+ qCWarning(Render::Rendering) << "AlphaTest not available with OpenGL 3.2 core";
+}
+
+void GraphicsHelperGL3_3::depthTest(GLenum mode)
+{
+ m_funcs->glEnable(GL_DEPTH_TEST);
+ m_funcs->glDepthFunc(mode);
+}
+
+void GraphicsHelperGL3_3::depthMask(GLenum mode)
+{
+ m_funcs->glDepthMask(mode);
+}
+
+void GraphicsHelperGL3_3::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
+void GraphicsHelperGL3_3::frontFace(GLenum mode)
+{
+ m_funcs->glFrontFace(mode);
+
+}
+
+void GraphicsHelperGL3_3::setMSAAEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_MULTISAMPLE)
+ : m_funcs->glDisable(GL_MULTISAMPLE);
+}
+
+void GraphicsHelperGL3_3::setAlphaCoverageEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
+ : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+}
+
+GLuint GraphicsHelperGL3_3::createFrameBufferObject()
+{
+ GLuint id;
+ m_funcs->glGenFramebuffers(1, &id);
+ return id;
+}
+
+void GraphicsHelperGL3_3::releaseFrameBufferObject(GLuint frameBufferId)
+{
+ m_funcs->glDeleteFramebuffers(1, &frameBufferId);
+}
+
+void GraphicsHelperGL3_3::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode)
+{
+ switch (mode) {
+ case FBODraw:
+ m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBORead:
+ m_funcs->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBOReadAndDraw:
+ default:
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+ return;
+ }
+}
+
+GLuint GraphicsHelperGL3_3::boundFrameBufferObject()
+{
+ GLint id = 0;
+ m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id);
+ return id;
+}
+
+bool GraphicsHelperGL3_3::checkFrameBufferComplete()
+{
+ return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+bool GraphicsHelperGL3_3::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
+void GraphicsHelperGL3_3::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+
+ texture->bind();
+ QOpenGLTexture::Target target = texture->target();
+ if (target == QOpenGLTexture::Target1DArray || target == QOpenGLTexture::Target2DArray ||
+ target == QOpenGLTexture::Target2DMultisampleArray || target == QOpenGLTexture::Target3D)
+ m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMapArray)
+ m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces)
+ m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
+ texture->release();
+}
+
+void GraphicsHelperGL3_3::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
+bool GraphicsHelperGL3_3::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case MRT:
+ case UniformBufferObject:
+ case PrimitiveRestart:
+ case RenderBufferDimensionRetrieval:
+ case TextureDimensionRetrieval:
+ case BindableFragmentOutputs:
+ case BlitFramebuffer:
+ case Fences:
+ return true;
+ case Tessellation:
+ return !m_tessFuncs.isNull();
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperGL3_3::drawBuffers(GLsizei n, const int *bufs)
+{
+ // Use QVarLengthArray here
+ QVarLengthArray<GLenum, 16> drawBufs(n);
+
+ for (int i = 0; i < n; i++)
+ drawBufs[i] = GL_COLOR_ATTACHMENT0 + bufs[i];
+ m_funcs->glDrawBuffers(n, drawBufs.constData());
+}
+
+void GraphicsHelperGL3_3::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs)
+{
+ for (auto it = outputs.begin(), end = outputs.end(); it != end; ++it)
+ m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str());
+}
+
+void GraphicsHelperGL3_3::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsHelperGL3_3::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ Q_UNUSED(programId);
+ Q_UNUSED(shaderStorageBlockIndex);
+ Q_UNUSED(shaderStorageBlockBinding);
+ qWarning() << "SSBO are not supported by OpenGL 3.3 (since OpenGL 4.3)";
+}
+
+void GraphicsHelperGL3_3::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ Q_UNUSED(imageUnit)
+ Q_UNUSED(texture)
+ Q_UNUSED(mipLevel)
+ Q_UNUSED(layered)
+ Q_UNUSED(layer)
+ Q_UNUSED(access)
+ Q_UNUSED(format)
+ qWarning() << "Shader Images are not supported by OpenGL 3.3 (since OpenGL 4.2)";
+}
+
+void GraphicsHelperGL3_3::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ m_funcs->glBindBufferBase(target, index, buffer);
+}
+
+void GraphicsHelperGL3_3::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+
+ case GL_FLOAT: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_FLOAT_VEC2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_FLOAT_VEC3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_FLOAT_VEC4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 3);
+ break;
+ }
+
+ case GL_INT: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_INT_VEC2: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_INT_VEC3: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_INT_VEC4: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_UNSIGNED_INT: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC2: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC3: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC4: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_BOOL: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_BOOL_VEC2: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_BOOL_VEC3: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_BOOL_VEC4: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY: {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name;
+ break;
+ }
+}
+
+uint GraphicsHelperGL3_3::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT2x4:
+ rawByteSize = matrixStride ? 2 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT4x2:
+ rawByteSize = matrixStride ? 4 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT2x3:
+ rawByteSize = matrixStride ? 2 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT3x2:
+ rawByteSize = matrixStride ? 3 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_FLOAT_MAT4x3:
+ rawByteSize = matrixStride ? 4 * matrixStride : 48;
+ break;
+
+ case GL_FLOAT_MAT3x4:
+ rawByteSize = matrixStride ? 3 * matrixStride : 48;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_UNSIGNED_INT:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ rawByteSize = 4;
+ break;
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void GraphicsHelperGL3_3::enableClipPlane(int clipPlane)
+{
+ m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL3_3::disableClipPlane(int clipPlane)
+{
+ m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL3_3::setClipPlane(int clipPlane, const QVector3D &normal, float distance)
+{
+ // deprecated
+ Q_UNUSED(clipPlane);
+ Q_UNUSED(normal);
+ Q_UNUSED(distance);
+}
+
+GLint GraphicsHelperGL3_3::maxClipPlaneCount()
+{
+ GLint max = 0;
+ m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max);
+ return max;
+}
+
+void GraphicsHelperGL3_3::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ Q_UNUSED(barriers);
+ qWarning() << "memory barrier is not supported by OpenGL 3.3 (since 4.3)";
+}
+
+void GraphicsHelperGL3_3::enablePrimitiveRestart(int primitiveRestartIndex)
+{
+ m_funcs->glPrimitiveRestartIndex(primitiveRestartIndex);
+ m_funcs->glEnable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL3_3::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
+void GraphicsHelperGL3_3::disablePrimitiveRestart()
+{
+ m_funcs->glDisable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL3_3::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ GLfloat vec[4] = {values[0], values[1], values[2], values[3]};
+ m_funcs->glClearBufferfv(GL_COLOR, drawbuffer, vec);
+}
+
+void GraphicsHelperGL3_3::pointSize(bool programmable, GLfloat value)
+{
+ if (programmable) {
+ m_funcs->glEnable(GL_PROGRAM_POINT_SIZE);
+ } else {
+ m_funcs->glDisable(GL_PROGRAM_POINT_SIZE);
+ m_funcs->glPointSize(value);
+ }
+}
+
+void GraphicsHelperGL3_3::enablei(GLenum cap, GLuint index)
+{
+ m_funcs->glEnablei(cap, index);
+}
+
+void GraphicsHelperGL3_3::disablei(GLenum cap, GLuint index)
+{
+ m_funcs->glDisablei(cap, index);
+}
+
+void GraphicsHelperGL3_3::setSeamlessCubemap(bool enable)
+{
+ if (enable)
+ m_funcs->glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ else
+ m_funcs->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+}
+
+QSize GraphicsHelperGL3_3::getRenderBufferDimensions(GLuint renderBufferId)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ return QSize(width, height);
+}
+
+QSize GraphicsHelperGL3_3::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindTexture(target, textureId);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ m_funcs->glBindTexture(target, 0);
+
+ return QSize(width, height);
+}
+
+void GraphicsHelperGL3_3::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ Q_UNUSED(wx);
+ Q_UNUSED(wy);
+ Q_UNUSED(wz);
+ qWarning() << "Compute Shaders are not supported by OpenGL 3.3 (since OpenGL 4.3)";
+}
+
+char *GraphicsHelperGL3_3::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+}
+
+GLboolean GraphicsHelperGL3_3::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
+void GraphicsHelperGL3_3::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform1fv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform2fv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform3fv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform4fv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform1iv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform2iv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform3iv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform4iv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform1uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform1uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform2uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform2uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform3uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform3uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniform4uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform4uiv(location, count, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL3_3::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x3fv(location, count, false, values);
+}
+
+UniformType GraphicsHelperGL3_3::uniformTypeFromGLType(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ return UniformType::Float;
+ case GL_FLOAT_VEC2:
+ return UniformType::Vec2;
+ case GL_FLOAT_VEC3:
+ return UniformType::Vec3;
+ case GL_FLOAT_VEC4:
+ return UniformType::Vec4;
+ case GL_FLOAT_MAT2:
+ return UniformType::Mat2;
+ case GL_FLOAT_MAT3:
+ return UniformType::Mat3;
+ case GL_FLOAT_MAT4:
+ return UniformType::Mat4;
+ case GL_FLOAT_MAT2x3:
+ return UniformType::Mat2x3;
+ case GL_FLOAT_MAT3x2:
+ return UniformType::Mat3x2;
+ case GL_FLOAT_MAT2x4:
+ return UniformType::Mat2x4;
+ case GL_FLOAT_MAT4x2:
+ return UniformType::Mat4x2;
+ case GL_FLOAT_MAT3x4:
+ return UniformType::Mat3x4;
+ case GL_FLOAT_MAT4x3:
+ return UniformType::Mat4x3;
+ case GL_INT:
+ return UniformType::Int;
+ case GL_INT_VEC2:
+ return UniformType::IVec2;
+ case GL_INT_VEC3:
+ return UniformType::IVec3;
+ case GL_INT_VEC4:
+ return UniformType::IVec4;
+ case GL_UNSIGNED_INT:
+ return UniformType::UInt;
+ case GL_UNSIGNED_INT_VEC2:
+ return UniformType::UIVec2;
+ case GL_UNSIGNED_INT_VEC3:
+ return UniformType::UIVec3;
+ case GL_UNSIGNED_INT_VEC4:
+ return UniformType::UIVec4;
+ case GL_BOOL:
+ return UniformType::Bool;
+ case GL_BOOL_VEC2:
+ return UniformType::BVec2;
+ case GL_BOOL_VEC3:
+ return UniformType::BVec3;
+ case GL_BOOL_VEC4:
+ return UniformType::BVec4;
+
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_2D_RECT:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_SAMPLER_3D:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ return UniformType::Sampler;
+ default:
+ Q_UNREACHABLE();
+ return UniformType::Float;
+ }
+}
+
+void GraphicsHelperGL3_3::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
new file mode 100644
index 000000000..8d8525111
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl3_3_p.h
@@ -0,0 +1,185 @@
+/****************************************************************************
+**
+** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERGL3_3_P_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERGL3_3_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperinterface_p.h>
+#include <QtCore/qscopedpointer.h>
+
+#ifndef QT_OPENGL_ES_2
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLFunctions_3_3_Core;
+class QOpenGLExtension_ARB_tessellation_shader;
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT GraphicsHelperGL3_3 : public GraphicsHelperInterface
+{
+public:
+ GraphicsHelperGL3_3();
+ ~GraphicsHelperGL3_3();
+
+ // QGraphicHelperInterface interface
+ void alphaTest(GLenum mode1, GLenum mode2) override;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blendEquation(GLenum mode) override;
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ GLuint boundFrameBufferObject() override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ bool checkFrameBufferComplete() override;
+ void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
+ GLuint createFrameBufferObject() override;
+ void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
+ void depthTest(GLenum mode) override;
+ void disableClipPlane(int clipPlane) override;
+ void disablei(GLenum cap, GLuint index) override;
+ void disablePrimitiveRestart() override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLint baseVertex = 0) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void enableClipPlane(int clipPlane) override;
+ void enablei(GLenum cap, GLuint index) override;
+ void enablePrimitiveRestart(int primitiveRestartIndex) override;
+ void enableVertexAttributeArray(int location) override;
+ void frontFace(GLenum mode) override;
+ QSize getRenderBufferDimensions(GLuint renderBufferId) override;
+ QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ void pointSize(bool programmable, GLfloat value) override;
+ GLint maxClipPlaneCount() override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+ void releaseFrameBufferObject(GLuint frameBufferId) override;
+ void setMSAAEnabled(bool enable) override;
+ void setAlphaCoverageEnabled(bool enable) override;
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance) override;
+ void setSeamlessCubemap(bool enable) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ bool supportsFeature(Feature feature) const override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void useProgram(GLuint programId) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ void glUniform1iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform2iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform3iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform4iv(GLint location, GLsizei count, const GLint *value) override;
+
+ void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) override;
+
+ void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+
+private:
+ QOpenGLFunctions_3_3_Core *m_funcs;
+ QScopedPointer<QOpenGLExtension_ARB_tessellation_shader> m_tessFuncs;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERGL3_3_P_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
new file mode 100644
index 000000000..775dd7935
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4.cpp
@@ -0,0 +1,1442 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "graphicshelpergl4_p.h"
+
+#ifndef QT_OPENGL_ES_2
+#include <QOpenGLFunctions_4_3_Core>
+#include <QtOpenGLExtensions/qopenglextensions.h>
+#include <Qt3DRender/private/renderlogging_p.h>
+#include <private/attachmentpack_p.h>
+#include <qgraphicsutils_p.h>
+
+# ifndef QT_OPENGL_4_3
+# ifndef GL_PATCH_VERTICES
+# define GL_PATCH_VERTICES 36466
+# endif
+# define GL_ACTIVE_RESOURCES 0x92F5
+# define GL_BUFFER_BINDING 0x9302
+# define GL_BUFFER_DATA_SIZE 0x9303
+# define GL_NUM_ACTIVE_VARIABLES 0x9304
+# define GL_SHADER_STORAGE_BLOCK 0x92E6
+# define GL_UNIFORM 0x92E1
+# define GL_UNIFORM_BLOCK 0x92E2
+# define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+# define GL_UNIFORM_OFFSET 0x8A3B
+# define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+# define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+# define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+# define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+# define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+# define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+# define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+# define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+# define GL_UNIFORM_BARRIER_BIT 0x00000004
+# define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+# define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+# define GL_COMMAND_BARRIER_BIT 0x00000040
+# define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+# define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+# define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+# define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+# define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+# define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+# define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+# define GL_QUERY_BUFFER_BARRIER_BIT 0x00008000
+# define GL_IMAGE_1D 0x904C
+# define GL_IMAGE_2D 0x904D
+# define GL_IMAGE_3D 0x904E
+# define GL_IMAGE_2D_RECT 0x904F
+# define GL_IMAGE_CUBE 0x9050
+# define GL_IMAGE_BUFFER 0x9051
+# define GL_IMAGE_1D_ARRAY 0x9052
+# define GL_IMAGE_2D_ARRAY 0x9053
+# define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+# define GL_IMAGE_2D_MULTISAMPLE 0x9055
+# define GL_IMAGE_2D_MULTISAMPLE_ARRAY 0x9056
+# define GL_INT_IMAGE_1D 0x9057
+# define GL_INT_IMAGE_2D 0x9058
+# define GL_INT_IMAGE_3D 0x9059
+# define GL_INT_IMAGE_2D_RECT 0x905A
+# define GL_INT_IMAGE_CUBE 0x905B
+# define GL_INT_IMAGE_BUFFER 0x905C
+# define GL_INT_IMAGE_1D_ARRAY 0x905D
+# define GL_INT_IMAGE_2D_ARRAY 0x905E
+# define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+# define GL_INT_IMAGE_2D_MULTISAMPLE 0x9060
+# define GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x9061
+# define GL_UNSIGNED_INT_IMAGE_1D 0x9062
+# define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+# define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+# define GL_UNSIGNED_INT_IMAGE_2D_RECT 0x9065
+# define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+# define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+# define GL_UNSIGNED_INT_IMAGE_1D_ARRAY 0x9068
+# define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+# define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+# define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE 0x906B
+# define GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY 0x906C
+# endif
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+namespace {
+
+GLbitfield memoryBarrierGLBitfield(QMemoryBarrier::Operations barriers)
+{
+ GLbitfield bits = 0;
+
+ if (barriers.testFlag(QMemoryBarrier::All)) {
+ bits |= GL_ALL_BARRIER_BITS;
+ return bits;
+ }
+
+ if (barriers.testFlag(QMemoryBarrier::VertexAttributeArray))
+ bits |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ElementArray))
+ bits |= GL_ELEMENT_ARRAY_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::Uniform))
+ bits |= GL_UNIFORM_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TextureFetch))
+ bits |= GL_TEXTURE_FETCH_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ShaderImageAccess))
+ bits |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::Command))
+ bits |= GL_COMMAND_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::PixelBuffer))
+ bits |= GL_PIXEL_BUFFER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TextureUpdate))
+ bits |= GL_TEXTURE_UPDATE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::BufferUpdate))
+ bits |= GL_BUFFER_UPDATE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::FrameBuffer))
+ bits |= GL_FRAMEBUFFER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::TransformFeedback))
+ bits |= GL_TRANSFORM_FEEDBACK_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::AtomicCounter))
+ bits |= GL_ATOMIC_COUNTER_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::ShaderStorage))
+ bits |= GL_SHADER_STORAGE_BARRIER_BIT;
+ if (barriers.testFlag(QMemoryBarrier::QueryBuffer))
+ bits |= GL_QUERY_BUFFER_BARRIER_BIT;
+
+ return bits;
+}
+
+}
+
+GraphicsHelperGL4::GraphicsHelperGL4()
+ : m_funcs(nullptr)
+{
+}
+
+void GraphicsHelperGL4::initializeHelper(QOpenGLContext *context,
+ QAbstractOpenGLFunctions *functions)
+{
+ Q_UNUSED(context);
+ m_funcs = static_cast<QOpenGLFunctions_4_3_Core*>(functions);
+ const bool ok = m_funcs->initializeOpenGLFunctions();
+ Q_ASSERT(ok);
+ Q_UNUSED(ok);
+}
+
+void GraphicsHelperGL4::drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLsizei instances,
+ GLint baseVertex,
+ GLint baseInstance)
+{
+ if (baseInstance != 0)
+ qWarning() << "glDrawElementsInstancedBaseVertexBaseInstance is not supported with OpenGL ES 2";
+
+ // glDrawElements OpenGL 3.1 or greater
+ m_funcs->glDrawElementsInstancedBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ instances,
+ baseVertex);
+}
+
+void GraphicsHelperGL4::drawArraysInstanced(GLenum primitiveType,
+ GLint first,
+ GLsizei count,
+ GLsizei instances)
+{
+ // glDrawArraysInstanced OpenGL 3.1 or greater
+ m_funcs->glDrawArraysInstanced(primitiveType,
+ first,
+ count,
+ instances);
+}
+
+void GraphicsHelperGL4::drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance)
+{
+ m_funcs->glDrawArraysInstancedBaseInstance(primitiveType,
+ first,
+ count,
+ instances,
+ baseInstance);
+}
+
+void GraphicsHelperGL4::drawElements(GLenum primitiveType,
+ GLsizei primitiveCount,
+ GLint indexType,
+ void *indices,
+ GLint baseVertex)
+{
+ m_funcs->glDrawElementsBaseVertex(primitiveType,
+ primitiveCount,
+ indexType,
+ indices,
+ baseVertex);
+}
+
+void GraphicsHelperGL4::drawElementsIndirect(GLenum mode,
+ GLenum type,
+ void *indirect)
+{
+ m_funcs->glDrawElementsIndirect(mode, type, indirect);
+}
+
+void GraphicsHelperGL4::drawArrays(GLenum primitiveType,
+ GLint first,
+ GLsizei count)
+{
+ m_funcs->glDrawArrays(primitiveType,
+ first,
+ count);
+}
+
+void GraphicsHelperGL4::drawArraysIndirect(GLenum mode, void *indirect)
+{
+ m_funcs->glDrawArraysIndirect(mode, indirect);
+}
+
+void GraphicsHelperGL4::setVerticesPerPatch(GLint verticesPerPatch)
+{
+ m_funcs->glPatchParameteri(GL_PATCH_VERTICES, verticesPerPatch);
+}
+
+void GraphicsHelperGL4::useProgram(GLuint programId)
+{
+ m_funcs->glUseProgram(programId);
+}
+
+QVector<ShaderUniform> GraphicsHelperGL4::programUniformsAndLocations(GLuint programId)
+{
+ QVector<ShaderUniform> uniforms;
+
+ GLint nbrActiveUniforms = 0;
+ m_funcs->glGetProgramInterfaceiv(programId, GL_UNIFORM, GL_ACTIVE_RESOURCES, &nbrActiveUniforms);
+ uniforms.reserve(nbrActiveUniforms);
+ char uniformName[256];
+ for (GLint i = 0; i < nbrActiveUniforms; ++i) {
+ ShaderUniform uniform;
+ GLsizei uniformNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveUniform(programId, i, sizeof(uniformName) - 1, &uniformNameLength,
+ &uniform.m_size, &uniform.m_type, uniformName);
+ uniformName[sizeof(uniformName) - 1] = '\0';
+ uniform.m_location = m_funcs->glGetUniformLocation(programId, uniformName);
+ uniform.m_name = QString::fromUtf8(uniformName, uniformNameLength);
+ // Work around for uniform array names that aren't returned with [0] by some drivers
+ if (uniform.m_size > 1 && !uniform.m_name.endsWith(QLatin1String("[0]")))
+ uniform.m_name.append(QLatin1String("[0]"));
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_BLOCK_INDEX, &uniform.m_blockIndex);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_OFFSET, &uniform.m_offset);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_ARRAY_STRIDE, &uniform.m_arrayStride);
+ m_funcs->glGetActiveUniformsiv(programId, 1, (GLuint*)&i, GL_UNIFORM_MATRIX_STRIDE, &uniform.m_matrixStride);
+ uniform.m_rawByteSize = uniformByteSize(uniform);
+ uniforms.append(uniform);
+ qCDebug(Render::Rendering) << uniform.m_name << "size" << uniform.m_size
+ << " offset" << uniform.m_offset
+ << " rawSize" << uniform.m_rawByteSize;
+ }
+
+ return uniforms;
+}
+
+QVector<ShaderAttribute> GraphicsHelperGL4::programAttributesAndLocations(GLuint programId)
+{
+ QVector<ShaderAttribute> attributes;
+ GLint nbrActiveAttributes = 0;
+ m_funcs->glGetProgramiv(programId, GL_ACTIVE_ATTRIBUTES, &nbrActiveAttributes);
+ attributes.reserve(nbrActiveAttributes);
+ char attributeName[256];
+ for (GLint i = 0; i < nbrActiveAttributes; ++i) {
+ ShaderAttribute attribute;
+ GLsizei attributeNameLength = 0;
+ // Size is 1 for scalar and more for struct or arrays
+ // Type is the GL Type
+ m_funcs->glGetActiveAttrib(programId, i, sizeof(attributeName) - 1, &attributeNameLength,
+ &attribute.m_size, &attribute.m_type, attributeName);
+ attributeName[sizeof(attributeName) - 1] = '\0';
+ attribute.m_location = m_funcs->glGetAttribLocation(programId, attributeName);
+ attribute.m_name = QString::fromUtf8(attributeName, attributeNameLength);
+ attributes.append(attribute);
+ }
+ return attributes;
+}
+
+QVector<ShaderUniformBlock> GraphicsHelperGL4::programUniformBlocks(GLuint programId)
+{
+ QVector<ShaderUniformBlock> blocks;
+ GLint nbrActiveUniformsBlocks = 0;
+ m_funcs->glGetProgramInterfaceiv(programId, GL_UNIFORM_BLOCK, GL_ACTIVE_RESOURCES, &nbrActiveUniformsBlocks);
+ blocks.reserve(nbrActiveUniformsBlocks);
+ for (GLint i = 0; i < nbrActiveUniformsBlocks; ++i) {
+ QByteArray uniformBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderUniformBlock uniformBlock;
+ m_funcs->glGetProgramResourceName(programId, GL_UNIFORM_BLOCK, i, 256, &length, uniformBlockName.data());
+ uniformBlock.m_name = QString::fromUtf8(uniformBlockName.left(length));
+ uniformBlock.m_index = i;
+ GLenum prop = GL_BUFFER_BINDING;
+ m_funcs->glGetProgramResourceiv(programId, GL_UNIFORM_BLOCK, i, 1, &prop, 4, NULL, &uniformBlock.m_binding);
+ prop = GL_BUFFER_DATA_SIZE;
+ m_funcs->glGetProgramResourceiv(programId, GL_UNIFORM_BLOCK, i, 1, &prop, 4, NULL, &uniformBlock.m_size);
+ prop = GL_NUM_ACTIVE_VARIABLES;
+ m_funcs->glGetProgramResourceiv(programId, GL_UNIFORM_BLOCK, i, 1, &prop, 4, NULL, &uniformBlock.m_activeUniformsCount);
+ blocks.append(uniformBlock);
+ }
+ return blocks;
+}
+
+QVector<ShaderStorageBlock> GraphicsHelperGL4::programShaderStorageBlocks(GLuint programId)
+{
+ QVector<ShaderStorageBlock> blocks;
+ GLint nbrActiveShaderStorageBlocks = 0;
+ m_funcs->glGetProgramInterfaceiv(programId, GL_SHADER_STORAGE_BLOCK, GL_ACTIVE_RESOURCES, &nbrActiveShaderStorageBlocks);
+ blocks.reserve(nbrActiveShaderStorageBlocks);
+ for (GLint i = 0; i < nbrActiveShaderStorageBlocks; ++i) {
+ QByteArray storageBlockName(256, '\0');
+ GLsizei length = 0;
+ ShaderStorageBlock storageBlock;
+ m_funcs->glGetProgramResourceName(programId, GL_SHADER_STORAGE_BLOCK, i, 256, &length, storageBlockName.data());
+ storageBlock.m_index = i;
+ storageBlock.m_name = QString::fromUtf8(storageBlockName.left(length));
+ GLenum prop = GL_BUFFER_BINDING;
+ m_funcs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_binding);
+ prop = GL_BUFFER_DATA_SIZE;
+ m_funcs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_size);
+ prop = GL_NUM_ACTIVE_VARIABLES;
+ m_funcs->glGetProgramResourceiv(programId, GL_SHADER_STORAGE_BLOCK, i, 1, &prop, 4, NULL, &storageBlock.m_activeVariablesCount);
+ blocks.push_back(storageBlock);
+ }
+ return blocks;
+}
+
+void GraphicsHelperGL4::vertexAttribDivisor(GLuint index, GLuint divisor)
+{
+ m_funcs->glVertexAttribDivisor(index, divisor);
+}
+
+void GraphicsHelperGL4::vertexAttributePointer(GLenum shaderDataType,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const GLvoid *pointer)
+{
+ switch (shaderDataType) {
+ case GL_FLOAT:
+ case GL_FLOAT_VEC2:
+ case GL_FLOAT_VEC3:
+ case GL_FLOAT_VEC4:
+ case GL_FLOAT_MAT2:
+ case GL_FLOAT_MAT2x3:
+ case GL_FLOAT_MAT2x4:
+ case GL_FLOAT_MAT3:
+ case GL_FLOAT_MAT3x2:
+ case GL_FLOAT_MAT3x4:
+ case GL_FLOAT_MAT4x2:
+ case GL_FLOAT_MAT4x3:
+ case GL_FLOAT_MAT4:
+ m_funcs->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+ break;
+
+ case GL_INT:
+ case GL_INT_VEC2:
+ case GL_INT_VEC3:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT:
+ case GL_UNSIGNED_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC4:
+ m_funcs->glVertexAttribIPointer(index, size, type, stride, pointer);
+ break;
+
+ case GL_DOUBLE:
+ case GL_DOUBLE_VEC2:
+ case GL_DOUBLE_VEC3:
+ case GL_DOUBLE_VEC4:
+ m_funcs->glVertexAttribLPointer(index, size, type, stride, pointer);
+ break;
+
+ default:
+ qCWarning(Render::Rendering) << "vertexAttribPointer: Unhandled type";
+ Q_UNREACHABLE();
+ }
+}
+
+void GraphicsHelperGL4::readBuffer(GLenum mode)
+{
+ m_funcs->glReadBuffer(mode);
+}
+
+void GraphicsHelperGL4::drawBuffer(GLenum mode)
+{
+ m_funcs->glDrawBuffer(mode);
+}
+
+void *GraphicsHelperGL4::fenceSync()
+{
+ return m_funcs->glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+void GraphicsHelperGL4::clientWaitSync(void *sync, GLuint64 nanoSecTimeout)
+{
+ qDebug() << Q_FUNC_INFO << sync << static_cast<GLsync>(sync);
+ GLenum e = m_funcs->glClientWaitSync(static_cast<GLsync>(sync), GL_SYNC_FLUSH_COMMANDS_BIT, nanoSecTimeout);
+ qDebug() << e;
+}
+
+void GraphicsHelperGL4::waitSync(void *sync)
+{
+ m_funcs->glWaitSync(static_cast<GLsync>(sync), 0, GL_TIMEOUT_IGNORED);
+}
+
+bool GraphicsHelperGL4::wasSyncSignaled(void *sync)
+{
+ GLint v = 0;
+ m_funcs->glGetSynciv(static_cast<GLsync>(sync),
+ GL_SYNC_STATUS,
+ sizeof(v),
+ nullptr,
+ &v);
+ return v == GL_SIGNALED;
+}
+
+void GraphicsHelperGL4::deleteSync(void *sync)
+{
+ m_funcs->glDeleteSync(static_cast<GLsync>(sync));
+}
+
+void GraphicsHelperGL4::rasterMode(GLenum faceMode, GLenum rasterMode)
+{
+ m_funcs->glPolygonMode(faceMode, rasterMode);
+}
+
+void GraphicsHelperGL4::glUniform1fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform1fv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform2fv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform3fv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniform4fv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform1iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform1iv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform2iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform2iv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform3iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform3iv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform4iv(GLint location, GLsizei count, const GLint *values)
+{
+ m_funcs->glUniform4iv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform1uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform1uiv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform2uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform2uiv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform3uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform3uiv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniform4uiv(GLint location, GLsizei count, const GLuint *values)
+{
+ m_funcs->glUniform4uiv(location, count, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x3fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix2x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x2fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix3x4fv(location, count, false, values);
+}
+
+void GraphicsHelperGL4::glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *values)
+{
+ m_funcs->glUniformMatrix4x3fv(location, count, false, values);
+}
+
+UniformType GraphicsHelperGL4::uniformTypeFromGLType(GLenum type)
+{
+ switch (type) {
+ case GL_FLOAT:
+ return UniformType::Float;
+ case GL_FLOAT_VEC2:
+ return UniformType::Vec2;
+ case GL_FLOAT_VEC3:
+ return UniformType::Vec3;
+ case GL_FLOAT_VEC4:
+ return UniformType::Vec4;
+ case GL_FLOAT_MAT2:
+ return UniformType::Mat2;
+ case GL_FLOAT_MAT3:
+ return UniformType::Mat3;
+ case GL_FLOAT_MAT4:
+ return UniformType::Mat4;
+ case GL_FLOAT_MAT2x3:
+ return UniformType::Mat2x3;
+ case GL_FLOAT_MAT3x2:
+ return UniformType::Mat3x2;
+ case GL_FLOAT_MAT2x4:
+ return UniformType::Mat2x4;
+ case GL_FLOAT_MAT4x2:
+ return UniformType::Mat4x2;
+ case GL_FLOAT_MAT3x4:
+ return UniformType::Mat3x4;
+ case GL_FLOAT_MAT4x3:
+ return UniformType::Mat4x3;
+ case GL_INT:
+ return UniformType::Int;
+ case GL_INT_VEC2:
+ return UniformType::IVec2;
+ case GL_INT_VEC3:
+ return UniformType::IVec3;
+ case GL_INT_VEC4:
+ return UniformType::IVec4;
+ case GL_UNSIGNED_INT:
+ return UniformType::UInt;
+ case GL_UNSIGNED_INT_VEC2:
+ return UniformType::UIVec2;
+ case GL_UNSIGNED_INT_VEC3:
+ return UniformType::UIVec3;
+ case GL_UNSIGNED_INT_VEC4:
+ return UniformType::UIVec4;
+ case GL_BOOL:
+ return UniformType::Bool;
+ case GL_BOOL_VEC2:
+ return UniformType::BVec2;
+ case GL_BOOL_VEC3:
+ return UniformType::BVec3;
+ case GL_BOOL_VEC4:
+ return UniformType::BVec4;
+
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_2D_RECT:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_CUBE_MAP_ARRAY:
+ case GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_CUBE_MAP_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY:
+ return UniformType::Sampler;
+
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ return UniformType::Image;
+
+ default:
+ // TO DO: Add support for Doubles and Images
+ Q_UNREACHABLE();
+ return UniformType::Float;
+ }
+}
+
+void GraphicsHelperGL4::blendEquation(GLenum mode)
+{
+ m_funcs->glBlendEquation(mode);
+}
+
+void GraphicsHelperGL4::blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor)
+{
+ m_funcs->glBlendFunci(buf, sfactor, dfactor);
+}
+
+void GraphicsHelperGL4::blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha)
+{
+ m_funcs->glBlendFuncSeparatei(buf, sRGB, dRGB, sAlpha, dAlpha);
+}
+
+void GraphicsHelperGL4::alphaTest(GLenum, GLenum)
+{
+ qCWarning(Render::Rendering) << "AlphaTest not available with OpenGL 3.2 core";
+}
+
+void GraphicsHelperGL4::depthTest(GLenum mode)
+{
+ m_funcs->glEnable(GL_DEPTH_TEST);
+ m_funcs->glDepthFunc(mode);
+}
+
+void GraphicsHelperGL4::depthMask(GLenum mode)
+{
+ m_funcs->glDepthMask(mode);
+}
+
+void GraphicsHelperGL4::depthRange(GLdouble nearValue, GLdouble farValue)
+{
+ m_funcs->glDepthRange(nearValue, farValue);
+}
+
+void GraphicsHelperGL4::frontFace(GLenum mode)
+{
+ m_funcs->glFrontFace(mode);
+
+}
+
+void GraphicsHelperGL4::setMSAAEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_MULTISAMPLE)
+ : m_funcs->glDisable(GL_MULTISAMPLE);
+}
+
+void GraphicsHelperGL4::setAlphaCoverageEnabled(bool enabled)
+{
+ enabled ? m_funcs->glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
+ : m_funcs->glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
+}
+
+GLuint GraphicsHelperGL4::createFrameBufferObject()
+{
+ GLuint id;
+ m_funcs->glGenFramebuffers(1, &id);
+ return id;
+}
+
+void GraphicsHelperGL4::releaseFrameBufferObject(GLuint frameBufferId)
+{
+ m_funcs->glDeleteFramebuffers(1, &frameBufferId);
+}
+
+void GraphicsHelperGL4::bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode)
+{
+ switch (mode) {
+ case FBODraw:
+ m_funcs->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBORead:
+ m_funcs->glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBufferId);
+ return;
+ case FBOReadAndDraw:
+ default:
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, frameBufferId);
+ return;
+ }
+}
+
+void GraphicsHelperGL4::bindImageTexture(GLuint imageUnit, GLuint texture,
+ GLint mipLevel, GLboolean layered,
+ GLint layer, GLenum access, GLenum format)
+{
+ m_funcs->glBindImageTexture(imageUnit,
+ texture,
+ mipLevel,
+ layered,
+ layer,
+ access,
+ format);
+}
+
+GLuint GraphicsHelperGL4::boundFrameBufferObject()
+{
+ GLint id = 0;
+ m_funcs->glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &id);
+ return id;
+}
+
+bool GraphicsHelperGL4::checkFrameBufferComplete()
+{
+ return (m_funcs->glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+}
+
+bool GraphicsHelperGL4::frameBufferNeedsRenderBuffer(const Attachment &attachment)
+{
+ Q_UNUSED(attachment);
+ return false;
+}
+
+void GraphicsHelperGL4::bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment)
+{
+ GLenum attr = GL_DEPTH_STENCIL_ATTACHMENT;
+
+ if (attachment.m_point <= QRenderTargetOutput::Color15)
+ attr = GL_COLOR_ATTACHMENT0 + attachment.m_point;
+ else if (attachment.m_point == QRenderTargetOutput::Depth)
+ attr = GL_DEPTH_ATTACHMENT;
+ else if (attachment.m_point == QRenderTargetOutput::Stencil)
+ attr = GL_STENCIL_ATTACHMENT;
+
+ texture->bind();
+ QOpenGLTexture::Target target = texture->target();
+ if (target == QOpenGLTexture::Target1DArray || target == QOpenGLTexture::Target2DArray ||
+ target == QOpenGLTexture::Target2DMultisampleArray || target == QOpenGLTexture::Target3D)
+ m_funcs->glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMapArray)
+ m_funcs->glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel, attachment.m_layer);
+ else if (target == QOpenGLTexture::TargetCubeMap && attachment.m_face != QAbstractTexture::AllFaces)
+ m_funcs->glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, attr, attachment.m_face, texture->textureId(), attachment.m_mipLevel);
+ else
+ m_funcs->glFramebufferTexture(GL_DRAW_FRAMEBUFFER, attr, texture->textureId(), attachment.m_mipLevel);
+ texture->release();
+}
+
+void GraphicsHelperGL4::bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment)
+{
+ Q_UNUSED(renderBuffer);
+ Q_UNUSED(attachment);
+ Q_UNREACHABLE();
+}
+
+bool GraphicsHelperGL4::supportsFeature(GraphicsHelperInterface::Feature feature) const
+{
+ switch (feature) {
+ case MRT:
+ case Tessellation:
+ case UniformBufferObject:
+ case BindableFragmentOutputs:
+ case PrimitiveRestart:
+ case RenderBufferDimensionRetrieval:
+ case TextureDimensionRetrieval:
+ case ShaderStorageObject:
+ case Compute:
+ case DrawBuffersBlend:
+ case BlitFramebuffer:
+ case IndirectDrawing:
+ case MapBuffer:
+ case Fences:
+ case ShaderImage:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void GraphicsHelperGL4::drawBuffers(GLsizei n, const int *bufs)
+{
+ // Use QVarLengthArray here
+ QVarLengthArray<GLenum, 16> drawBufs(n);
+
+ for (int i = 0; i < n; i++)
+ drawBufs[i] = GL_COLOR_ATTACHMENT0 + bufs[i];
+ m_funcs->glDrawBuffers(n, drawBufs.constData());
+}
+
+void GraphicsHelperGL4::bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs)
+{
+ for (auto it = outputs.begin(), end = outputs.end(); it != end; ++it)
+ m_funcs->glBindFragDataLocation(shader, it.value(), it.key().toStdString().c_str());
+}
+
+void GraphicsHelperGL4::bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+{
+ m_funcs->glUniformBlockBinding(programId, uniformBlockIndex, uniformBlockBinding);
+}
+
+void GraphicsHelperGL4::bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding)
+{
+ m_funcs->glShaderStorageBlockBinding(programId, shaderStorageBlockIndex, shaderStorageBlockBinding);
+}
+
+void GraphicsHelperGL4::bindBufferBase(GLenum target, GLuint index, GLuint buffer)
+{
+ m_funcs->glBindBufferBase(target, index, buffer);
+}
+
+void GraphicsHelperGL4::buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer)
+{
+ char *bufferData = buffer.data();
+
+ switch (description.m_type) {
+
+ case GL_FLOAT: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_FLOAT_VEC2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_FLOAT_VEC3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_FLOAT_VEC4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT2x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 2, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 9);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 3);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 6);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT3x4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 3, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 16);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 4);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x2: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 8);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 2);
+ break;
+ }
+
+ case GL_FLOAT_MAT4x3: {
+ const GLfloat *data = QGraphicsUtils::valueArrayFromVariant<GLfloat>(v, description.m_size, 12);
+ QGraphicsUtils::fillDataMatrixArray(bufferData, data, description, 4, 3);
+ break;
+ }
+
+ case GL_INT: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_INT_VEC2: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_INT_VEC3: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_INT_VEC4: {
+ const GLint *data = QGraphicsUtils::valueArrayFromVariant<GLint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_UNSIGNED_INT: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC2: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC3: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_UNSIGNED_INT_VEC4: {
+ const GLuint *data = QGraphicsUtils::valueArrayFromVariant<GLuint>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_BOOL: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 1);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 1);
+ break;
+ }
+
+ case GL_BOOL_VEC2: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 2);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 2);
+ break;
+ }
+
+ case GL_BOOL_VEC3: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 3);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 3);
+ break;
+ }
+
+ case GL_BOOL_VEC4: {
+ const GLboolean *data = QGraphicsUtils::valueArrayFromVariant<GLboolean>(v, description.m_size, 4);
+ QGraphicsUtils::fillDataArray(bufferData, data, description, 4);
+ break;
+ }
+
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY: {
+ Q_ASSERT(description.m_size == 1);
+ int value = v.toInt();
+ QGraphicsUtils::fillDataArray<GLint>(bufferData, &value, description, 1);
+ break;
+ }
+
+ default:
+ qWarning() << Q_FUNC_INFO << "unsupported uniform type:" << description.m_type << "for " << description.m_name;
+ break;
+ }
+}
+
+uint GraphicsHelperGL4::uniformByteSize(const ShaderUniform &description)
+{
+ uint rawByteSize = 0;
+ int arrayStride = qMax(description.m_arrayStride, 0);
+ int matrixStride = qMax(description.m_matrixStride, 0);
+
+ switch (description.m_type) {
+
+ case GL_FLOAT_VEC2:
+ case GL_INT_VEC2:
+ case GL_UNSIGNED_INT_VEC2:
+ rawByteSize = 8;
+ break;
+
+ case GL_FLOAT_VEC3:
+ case GL_INT_VEC3:
+ case GL_UNSIGNED_INT_VEC3:
+ rawByteSize = 12;
+ break;
+
+ case GL_FLOAT_VEC4:
+ case GL_INT_VEC4:
+ case GL_UNSIGNED_INT_VEC4:
+ rawByteSize = 16;
+ break;
+
+ case GL_FLOAT_MAT2:
+ rawByteSize = matrixStride ? 2 * matrixStride : 16;
+ break;
+
+ case GL_FLOAT_MAT2x4:
+ rawByteSize = matrixStride ? 2 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT4x2:
+ rawByteSize = matrixStride ? 4 * matrixStride : 32;
+ break;
+
+ case GL_FLOAT_MAT3:
+ rawByteSize = matrixStride ? 3 * matrixStride : 36;
+ break;
+
+ case GL_FLOAT_MAT2x3:
+ rawByteSize = matrixStride ? 2 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT3x2:
+ rawByteSize = matrixStride ? 3 * matrixStride : 24;
+ break;
+
+ case GL_FLOAT_MAT4:
+ rawByteSize = matrixStride ? 4 * matrixStride : 64;
+ break;
+
+ case GL_FLOAT_MAT4x3:
+ rawByteSize = matrixStride ? 4 * matrixStride : 48;
+ break;
+
+ case GL_FLOAT_MAT3x4:
+ rawByteSize = matrixStride ? 3 * matrixStride : 48;
+ break;
+
+ case GL_BOOL:
+ rawByteSize = 1;
+ break;
+
+ case GL_BOOL_VEC2:
+ rawByteSize = 2;
+ break;
+
+ case GL_BOOL_VEC3:
+ rawByteSize = 3;
+ break;
+
+ case GL_BOOL_VEC4:
+ rawByteSize = 4;
+ break;
+
+ case GL_INT:
+ case GL_FLOAT:
+ case GL_UNSIGNED_INT:
+ case GL_SAMPLER_1D:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_3D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_BUFFER:
+ case GL_SAMPLER_2D_RECT:
+ case GL_INT_SAMPLER_1D:
+ case GL_INT_SAMPLER_2D:
+ case GL_INT_SAMPLER_3D:
+ case GL_INT_SAMPLER_CUBE:
+ case GL_INT_SAMPLER_BUFFER:
+ case GL_INT_SAMPLER_2D_RECT:
+ case GL_UNSIGNED_INT_SAMPLER_1D:
+ case GL_UNSIGNED_INT_SAMPLER_2D:
+ case GL_UNSIGNED_INT_SAMPLER_3D:
+ case GL_UNSIGNED_INT_SAMPLER_CUBE:
+ case GL_UNSIGNED_INT_SAMPLER_BUFFER:
+ case GL_UNSIGNED_INT_SAMPLER_2D_RECT:
+ case GL_SAMPLER_1D_SHADOW:
+ case GL_SAMPLER_2D_SHADOW:
+ case GL_SAMPLER_CUBE_SHADOW:
+ case GL_SAMPLER_1D_ARRAY:
+ case GL_SAMPLER_2D_ARRAY:
+ case GL_INT_SAMPLER_1D_ARRAY:
+ case GL_INT_SAMPLER_2D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_1D_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
+ case GL_SAMPLER_1D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_ARRAY_SHADOW:
+ case GL_SAMPLER_2D_RECT_SHADOW:
+ case GL_SAMPLER_2D_MULTISAMPLE:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE:
+ case GL_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY:
+ case GL_IMAGE_1D:
+ case GL_IMAGE_2D:
+ case GL_IMAGE_3D:
+ case GL_IMAGE_2D_RECT:
+ case GL_IMAGE_CUBE:
+ case GL_IMAGE_BUFFER:
+ case GL_IMAGE_1D_ARRAY:
+ case GL_IMAGE_2D_ARRAY:
+ case GL_IMAGE_CUBE_MAP_ARRAY:
+ case GL_IMAGE_2D_MULTISAMPLE:
+ case GL_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_INT_IMAGE_1D:
+ case GL_INT_IMAGE_2D:
+ case GL_INT_IMAGE_3D:
+ case GL_INT_IMAGE_2D_RECT:
+ case GL_INT_IMAGE_CUBE:
+ case GL_INT_IMAGE_BUFFER:
+ case GL_INT_IMAGE_1D_ARRAY:
+ case GL_INT_IMAGE_2D_ARRAY:
+ case GL_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_1D:
+ case GL_UNSIGNED_INT_IMAGE_2D:
+ case GL_UNSIGNED_INT_IMAGE_3D:
+ case GL_UNSIGNED_INT_IMAGE_2D_RECT:
+ case GL_UNSIGNED_INT_IMAGE_CUBE:
+ case GL_UNSIGNED_INT_IMAGE_BUFFER:
+ case GL_UNSIGNED_INT_IMAGE_1D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE:
+ case GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY:
+ rawByteSize = 4;
+ break;
+
+ default: {
+ qWarning() << Q_FUNC_INFO << "unable to deduce rawByteSize for uniform type:" << description.m_type << "for uniform" << description.m_name;
+ break;
+ }
+
+ }
+
+ return arrayStride ? rawByteSize * arrayStride : rawByteSize;
+}
+
+void GraphicsHelperGL4::enableClipPlane(int clipPlane)
+{
+ m_funcs->glEnable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL4::disableClipPlane(int clipPlane)
+{
+ m_funcs->glDisable(GL_CLIP_DISTANCE0 + clipPlane);
+}
+
+void GraphicsHelperGL4::setClipPlane(int, const QVector3D &, float)
+{
+ // deprecated
+}
+
+GLint GraphicsHelperGL4::maxClipPlaneCount()
+{
+ GLint max = 0;
+ m_funcs->glGetIntegerv(GL_MAX_CLIP_DISTANCES, &max);
+ return max;
+}
+
+void GraphicsHelperGL4::memoryBarrier(QMemoryBarrier::Operations barriers)
+{
+ m_funcs->glMemoryBarrier(memoryBarrierGLBitfield(barriers));
+}
+
+void GraphicsHelperGL4::enablePrimitiveRestart(int primitiveRestartIndex)
+{
+ m_funcs->glPrimitiveRestartIndex(primitiveRestartIndex);
+ m_funcs->glEnable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL4::enableVertexAttributeArray(int location)
+{
+ m_funcs->glEnableVertexAttribArray(location);
+}
+
+void GraphicsHelperGL4::disablePrimitiveRestart()
+{
+ m_funcs->glDisable(GL_PRIMITIVE_RESTART);
+}
+
+void GraphicsHelperGL4::clearBufferf(GLint drawbuffer, const QVector4D &values)
+{
+ GLfloat vec[4] = {values[0], values[1], values[2], values[3]};
+ m_funcs->glClearBufferfv(GL_COLOR, drawbuffer, vec);
+}
+
+void GraphicsHelperGL4::pointSize(bool programmable, GLfloat value)
+{
+ if (programmable) {
+ m_funcs->glEnable(GL_PROGRAM_POINT_SIZE);
+ } else {
+ m_funcs->glDisable(GL_PROGRAM_POINT_SIZE);
+ m_funcs->glPointSize(value);
+ }
+}
+
+void GraphicsHelperGL4::enablei(GLenum cap, GLuint index)
+{
+ m_funcs->glEnablei(cap, index);
+}
+
+void GraphicsHelperGL4::disablei(GLenum cap, GLuint index)
+{
+ m_funcs->glDisablei(cap, index);
+}
+
+void GraphicsHelperGL4::setSeamlessCubemap(bool enable)
+{
+ if (enable)
+ m_funcs->glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+ else
+ m_funcs->glDisable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+}
+
+QSize GraphicsHelperGL4::getRenderBufferDimensions(GLuint renderBufferId)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, renderBufferId);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &width);
+ m_funcs->glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &height);
+ m_funcs->glBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ return QSize(width, height);
+}
+
+QSize GraphicsHelperGL4::getTextureDimensions(GLuint textureId, GLenum target, uint level)
+{
+ GLint width = 0;
+ GLint height = 0;
+
+ m_funcs->glBindTexture(target, textureId);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_WIDTH, &width);
+ m_funcs->glGetTexLevelParameteriv(target, level, GL_TEXTURE_HEIGHT, &height);
+ m_funcs->glBindTexture(target, 0);
+
+ return QSize(width, height);
+}
+
+void GraphicsHelperGL4::dispatchCompute(GLuint wx, GLuint wy, GLuint wz)
+{
+ m_funcs->glDispatchCompute(wx, wy, wz);
+}
+
+char *GraphicsHelperGL4::mapBuffer(GLenum target, GLsizeiptr size)
+{
+ return static_cast<char*>(m_funcs->glMapBufferRange(target, 0, size, GL_MAP_READ_BIT | GL_MAP_WRITE_BIT));
+}
+
+GLboolean GraphicsHelperGL4::unmapBuffer(GLenum target)
+{
+ return m_funcs->glUnmapBuffer(target);
+}
+
+void GraphicsHelperGL4::blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+{
+ m_funcs->glBlitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
new file mode 100644
index 000000000..02cb7e211
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpergl4_p.h
@@ -0,0 +1,182 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERGL4_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERGL4_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <graphicshelperinterface_p.h>
+#include <QtCore/qscopedpointer.h>
+
+#ifndef QT_OPENGL_ES_2
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLFunctions_4_3_Core;
+
+namespace Qt3DRender {
+namespace Render {
+
+class Q_AUTOTEST_EXPORT GraphicsHelperGL4 : public GraphicsHelperInterface
+{
+public:
+ GraphicsHelperGL4();
+
+ // QGraphicHelperInterface interface
+ void alphaTest(GLenum mode1, GLenum mode2) override;
+ void bindBufferBase(GLenum target, GLuint index, GLuint buffer) override;
+ void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) override;
+ bool frameBufferNeedsRenderBuffer(const Attachment &attachment) override;
+ void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) override;
+ void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) override;
+ void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) override;
+ void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) override;
+ void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) override;
+ void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) override;
+ void blendEquation(GLenum mode) override;
+ void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) override;
+ void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) override;
+ void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) override;
+ GLuint boundFrameBufferObject() override;
+ void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) override;
+ bool checkFrameBufferComplete() override;
+ void clearBufferf(GLint drawbuffer, const QVector4D &values) override;
+ GLuint createFrameBufferObject() override;
+ void depthMask(GLenum mode) override;
+ void depthRange(GLdouble nearValue, GLdouble farValue) override;
+ void depthTest(GLenum mode) override;
+ void disableClipPlane(int clipPlane) override;
+ void disablei(GLenum cap, GLuint index) override;
+ void disablePrimitiveRestart() override;
+ void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) override;
+ char *mapBuffer(GLenum target, GLsizeiptr size) override;
+ GLboolean unmapBuffer(GLenum target) override;
+ void drawArrays(GLenum primitiveType, GLint first, GLsizei count) override;
+ void drawArraysIndirect(GLenum mode,void *indirect) override;
+ void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) override;
+ void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseInstance) override;
+ void drawBuffers(GLsizei n, const int *bufs) override;
+ void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLint baseVertex = 0) override;
+ void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) override;
+ void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void *indices, GLsizei instances, GLint baseVertex = 0, GLint baseInstance = 0) override;
+ void enableClipPlane(int clipPlane) override;
+ void enablei(GLenum cap, GLuint index) override;
+ void enablePrimitiveRestart(int primitiveRestartIndex) override;
+ void enableVertexAttributeArray(int location) override;
+ void frontFace(GLenum mode) override;
+ QSize getRenderBufferDimensions(GLuint renderBufferId) override;
+ QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) override;
+ void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) override;
+ void pointSize(bool programmable, GLfloat value) override;
+ GLint maxClipPlaneCount() override;
+ void memoryBarrier(QMemoryBarrier::Operations barriers) override;
+ QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) override;
+ QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) override;
+ QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) override;
+ QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) override;
+ void releaseFrameBufferObject(GLuint frameBufferId) override;
+ void setMSAAEnabled(bool enable) override;
+ void setAlphaCoverageEnabled(bool enable) override;
+ void setClipPlane(int clipPlane, const QVector3D &normal, float distance) override;
+ void setSeamlessCubemap(bool enable) override;
+ void setVerticesPerPatch(GLint verticesPerPatch) override;
+ bool supportsFeature(Feature feature) const override;
+ uint uniformByteSize(const ShaderUniform &description) override;
+ void useProgram(GLuint programId) override;
+ void vertexAttribDivisor(GLuint index, GLuint divisor) override;
+ void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) override;
+ void readBuffer(GLenum mode) override;
+ void drawBuffer(GLenum mode) override;
+ void rasterMode(GLenum faceMode, GLenum rasterMode) override;
+
+ void *fenceSync() override;
+ void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) override;
+ void waitSync(void *sync) override;
+ bool wasSyncSignaled(void *sync) override;
+ void deleteSync(void *sync) override;
+
+ void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ void glUniform1iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform2iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform3iv(GLint location, GLsizei count, const GLint *value) override;
+ void glUniform4iv(GLint location, GLsizei count, const GLint *value) override;
+
+ void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) override;
+ void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) override;
+
+ void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) override;
+ void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) override;
+
+ UniformType uniformTypeFromGLType(GLenum glType) override;
+
+private:
+ QOpenGLFunctions_4_3_Core *m_funcs;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // !QT_OPENGL_ES_2
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERGL4_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
new file mode 100644
index 000000000..aa2b65c66
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelperinterface_p.h
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GRAPHICSHELPERINTERFACE_H
+#define QT3DRENDER_RENDER_GRAPHICSHELPERINTERFACE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QOpenGLFunctions>
+#include <QOpenGLTexture>
+#include <QVector>
+#include <shadervariables_p.h>
+#include <Qt3DRender/private/uniform_p.h>
+#include <Qt3DRender/qmemorybarrier.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+struct Attachment;
+class RenderBuffer;
+
+class GraphicsHelperInterface
+{
+public:
+ enum Feature {
+ MRT = 0,
+ Tessellation,
+ UniformBufferObject,
+ BindableFragmentOutputs,
+ PrimitiveRestart,
+ RenderBufferDimensionRetrieval,
+ TextureDimensionRetrieval,
+ ShaderStorageObject,
+ Compute,
+ DrawBuffersBlend,
+ BlitFramebuffer,
+ IndirectDrawing,
+ MapBuffer,
+ Fences,
+ ShaderImage
+ };
+
+ enum FBOBindMode {
+ FBODraw,
+ FBORead,
+ FBOReadAndDraw
+ };
+
+ virtual ~GraphicsHelperInterface() {}
+ virtual void alphaTest(GLenum mode1, GLenum mode2) = 0;
+ virtual void bindBufferBase(GLenum target, GLuint index, GLuint buffer) = 0;
+ virtual void bindFragDataLocation(GLuint shader, const QHash<QString, int> &outputs) = 0;
+ virtual bool frameBufferNeedsRenderBuffer(const Attachment &attachment) = 0;
+ virtual void bindFrameBufferAttachment(QOpenGLTexture *texture, const Attachment &attachment) = 0;
+ virtual void bindFrameBufferAttachment(RenderBuffer *renderBuffer, const Attachment &attachment) = 0;
+ virtual void bindFrameBufferObject(GLuint frameBufferId, FBOBindMode mode) = 0;
+ virtual void bindImageTexture(GLuint imageUnit, GLuint texture, GLint mipLevel, GLboolean layered, GLint layer, GLenum access, GLenum format) = 0;
+ virtual void bindShaderStorageBlock(GLuint programId, GLuint shaderStorageBlockIndex, GLuint shaderStorageBlockBinding) = 0;
+ virtual void bindUniformBlock(GLuint programId, GLuint uniformBlockIndex, GLuint uniformBlockBinding) = 0;
+ virtual void blendEquation(GLenum mode) = 0;
+ virtual void blendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) = 0;
+ virtual void blendFuncSeparatei(GLuint buf, GLenum sRGB, GLenum dRGB, GLenum sAlpha, GLenum dAlpha) = 0;
+ virtual void blitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) = 0;
+ virtual GLuint boundFrameBufferObject() = 0;
+ virtual void buildUniformBuffer(const QVariant &v, const ShaderUniform &description, QByteArray &buffer) = 0;
+ virtual bool checkFrameBufferComplete() = 0;
+ virtual void clearBufferf(GLint drawbuffer, const QVector4D &values) = 0;
+ virtual GLuint createFrameBufferObject() = 0;
+ virtual void depthRange(GLdouble nearValue, GLdouble farValue) = 0;
+ virtual void depthMask(GLenum mode) = 0;
+ virtual void depthTest(GLenum mode) = 0;
+ virtual void disableClipPlane(int clipPlane) = 0;
+ virtual void disablei(GLenum cap, GLuint index) = 0;
+ virtual void disablePrimitiveRestart() = 0;
+ virtual void dispatchCompute(GLuint wx, GLuint wy, GLuint wz) = 0;
+ virtual char *mapBuffer(GLenum target, GLsizeiptr size) = 0;
+ virtual GLboolean unmapBuffer(GLenum target) = 0;
+ virtual void drawArrays(GLenum primitiveType, GLint first, GLsizei count) = 0;
+ virtual void drawArraysIndirect(GLenum mode,void *indirect) = 0;
+ virtual void drawArraysInstanced(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances) = 0;
+ virtual void drawArraysInstancedBaseInstance(GLenum primitiveType, GLint first, GLsizei count, GLsizei instances, GLsizei baseinstance) = 0;
+ virtual void drawBuffers(GLsizei n, const int *bufs) = 0;
+ virtual void drawElements(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices, GLint baseVertex) = 0;
+ virtual void drawElementsIndirect(GLenum mode, GLenum type, void *indirect) = 0;
+ virtual void drawElementsInstancedBaseVertexBaseInstance(GLenum primitiveType, GLsizei primitiveCount, GLint indexType, void * indices, GLsizei instances, GLint baseVertex, GLint baseInstance) = 0;
+ virtual void enableClipPlane(int clipPlane) = 0;
+ virtual void enablei(GLenum cap, GLuint index) = 0;
+ virtual void enablePrimitiveRestart(int primitiveRestartIndex) = 0;
+ virtual void enableVertexAttributeArray(int location) = 0;
+ virtual void frontFace(GLenum mode) = 0;
+ virtual QSize getRenderBufferDimensions(GLuint renderBufferId) = 0;
+ virtual QSize getTextureDimensions(GLuint textureId, GLenum target, uint level = 0) = 0;
+ virtual void initializeHelper(QOpenGLContext *context, QAbstractOpenGLFunctions *functions) = 0;
+ virtual GLint maxClipPlaneCount() = 0;
+ virtual void memoryBarrier(QMemoryBarrier::Operations barriers) = 0;
+ virtual void pointSize(bool programmable, GLfloat value) = 0;
+ virtual QVector<ShaderAttribute> programAttributesAndLocations(GLuint programId) = 0;
+ virtual QVector<ShaderUniform> programUniformsAndLocations(GLuint programId) = 0;
+ virtual QVector<ShaderUniformBlock> programUniformBlocks(GLuint programId) = 0;
+ virtual QVector<ShaderStorageBlock> programShaderStorageBlocks(GLuint programId) = 0;
+ virtual void releaseFrameBufferObject(GLuint frameBufferId) = 0;
+ virtual void setAlphaCoverageEnabled(bool enable) = 0;
+ virtual void setClipPlane(int clipPlane, const QVector3D &normal, float distance) = 0;
+ virtual void setMSAAEnabled(bool enable) = 0;
+ virtual void setSeamlessCubemap(bool enable) = 0;
+ virtual void setVerticesPerPatch(GLint verticesPerPatch) = 0;
+ virtual bool supportsFeature(Feature feature) const = 0;
+ virtual uint uniformByteSize(const ShaderUniform &description) = 0;
+ virtual void useProgram(GLuint programId) = 0;
+ virtual void vertexAttribDivisor(GLuint index, GLuint divisor) = 0;
+ virtual void vertexAttributePointer(GLenum shaderDataType, GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer) = 0;
+ virtual void readBuffer(GLenum mode) = 0;
+ virtual void drawBuffer(GLenum mode) = 0;
+ virtual void rasterMode(GLenum faceMode, GLenum rasterMode) = 0;
+
+ virtual void *fenceSync() = 0;
+ virtual void clientWaitSync(void *sync, GLuint64 nanoSecTimeout) = 0;
+ virtual void waitSync(void *sync) = 0;
+ virtual bool wasSyncSignaled(void *sync) = 0;
+ virtual void deleteSync(void *sync) = 0;
+
+ virtual void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+
+ virtual void glUniform1iv(GLint location, GLsizei count, const GLint *value) = 0;
+ virtual void glUniform2iv(GLint location, GLsizei count, const GLint *value) = 0;
+ virtual void glUniform3iv(GLint location, GLsizei count, const GLint *value) = 0;
+ virtual void glUniform4iv(GLint location, GLsizei count, const GLint *value) = 0;
+
+ virtual void glUniform1uiv(GLint location, GLsizei count, const GLuint *value) = 0;
+ virtual void glUniform2uiv(GLint location, GLsizei count, const GLuint *value) = 0;
+ virtual void glUniform3uiv(GLint location, GLsizei count, const GLuint *value) = 0;
+ virtual void glUniform4uiv(GLint location, GLsizei count, const GLuint *value) = 0;
+
+ virtual void glUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix2x3fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix3x2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix2x4fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix4x2fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix3x4fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+ virtual void glUniformMatrix4x3fv(GLint location, GLsizei count, const GLfloat *value) = 0;
+
+ virtual UniformType uniformTypeFromGLType(GLenum glType) = 0;
+};
+
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GRAPHICSHELPERINTERFACE_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/graphicshelpers.pri b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpers.pri
new file mode 100644
index 000000000..3cfa445ce
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/graphicshelpers.pri
@@ -0,0 +1,33 @@
+#DEFINES += QT3D_RENDER_ASPECT_OPENGL_DEBUG
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/graphicscontext_p.h \
+ $$PWD/graphicshelperinterface_p.h \
+ $$PWD/graphicshelperes2_p.h \
+ $$PWD/graphicshelperes3_p.h \
+ $$PWD/graphicshelperes3_1_p.h \
+ $$PWD/graphicshelperes3_2_p.h \
+ $$PWD/graphicshelpergl2_p.h \
+ $$PWD/graphicshelpergl3_3_p.h \
+ $$PWD/graphicshelpergl4_p.h \
+ $$PWD/graphicshelpergl3_2_p.h \
+ $$PWD/imagesubmissioncontext_p.h \
+ $$PWD/submissioncontext_p.h \
+ $$PWD/texturesubmissioncontext_p.h \
+ $$PWD/qgraphicsutils_p.h
+
+SOURCES += \
+ $$PWD/graphicscontext.cpp \
+ $$PWD/graphicshelperes2.cpp \
+ $$PWD/graphicshelperes3.cpp \
+ $$PWD/graphicshelperes3_1.cpp \
+ $$PWD/graphicshelperes3_2.cpp \
+ $$PWD/graphicshelpergl2.cpp \
+ $$PWD/graphicshelpergl3_3.cpp \
+ $$PWD/graphicshelpergl4.cpp \
+ $$PWD/graphicshelpergl3_2.cpp \
+ $$PWD/imagesubmissioncontext.cpp \
+ $$PWD/submissioncontext.cpp \
+ $$PWD/texturesubmissioncontext.cpp
diff --git a/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp b/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
new file mode 100644
index 000000000..cd2b33fb4
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "imagesubmissioncontext_p.h"
+#include <Qt3DRender/private/shaderimage_p.h>
+#include <Qt3DRender/qshaderimage.h>
+#include <graphicscontext_p.h>
+#include <gltexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// ES 3.1+ or GL 4.2+
+#ifndef GL_READ_ONLY
+#define GL_READ_ONLY 0x88B8
+#endif
+#ifndef GL_WRITE_ONLY
+#define GL_WRITE_ONLY 0x88B9
+#endif
+#ifndef GL_READ_WRITE
+#define GL_READ_WRITE 0x88BA
+#endif
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+
+namespace {
+
+GLenum glAccessEnumForShaderImageAccess(QShaderImage::Access access)
+{
+ switch (access) {
+ case QShaderImage::ReadOnly:
+ return GL_READ_ONLY;
+ case QShaderImage::WriteOnly:
+ return GL_WRITE_ONLY;
+ case QShaderImage::ReadWrite:
+ default:
+ break;
+ }
+ return GL_READ_WRITE;
+}
+
+GLenum glImageFormatToGL(QShaderImage::ImageFormat format)
+{
+ // Right now we can abuse from the fact that the ImageFormat enum values
+ // have been assigned the same value as the GL enum
+ return GLenum(format);
+}
+
+GLenum glImageFormatForShaderImageFormat(QShaderImage::ImageFormat format,
+ QAbstractTexture::TextureFormat textureFormat)
+{
+ Q_ASSERT_X(format != QShaderImage::NoFormat, Q_FUNC_INFO, "Valid image format or Automatic expected");
+
+ if (format != QShaderImage::Automatic)
+ return glImageFormatToGL(format);
+
+ // Otherwise try to mind to best texture format
+ switch (textureFormat) {
+ case QAbstractTexture::R8_UNorm:
+ return glImageFormatToGL(QShaderImage::R8_UNorm);
+ case QAbstractTexture::RG8_UNorm:
+ return glImageFormatToGL(QShaderImage::RG8_UNorm);
+ case QAbstractTexture::RGBA8_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_UNorm);
+
+ case QAbstractTexture::R16_UNorm:
+ return glImageFormatToGL(QShaderImage::R16_UNorm);
+ case QAbstractTexture::RG16_UNorm:
+ return glImageFormatToGL(QShaderImage::RG16_UNorm);
+ case QAbstractTexture::RGBA16_UNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_UNorm);
+
+ case QAbstractTexture::R8_SNorm:
+ return glImageFormatToGL(QShaderImage::R8_SNorm);
+ case QAbstractTexture::RG8_SNorm:
+ return glImageFormatToGL(QShaderImage::RG8_SNorm);
+ case QAbstractTexture::RGBA8_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA8_SNorm);
+
+ case QAbstractTexture::R16_SNorm:
+ return glImageFormatToGL(QShaderImage::R16_SNorm);
+ case QAbstractTexture::RG16_SNorm:
+ return glImageFormatToGL(QShaderImage::RG16_SNorm);
+ case QAbstractTexture::RGBA16_SNorm:
+ return glImageFormatToGL(QShaderImage::RGBA16_SNorm);
+
+ case QAbstractTexture::R8U:
+ return glImageFormatToGL(QShaderImage::R8U);
+ case QAbstractTexture::RG8U:
+ return glImageFormatToGL(QShaderImage::RG8U);
+ case QAbstractTexture::RGBA8U:
+ return glImageFormatToGL(QShaderImage::RGBA8U);
+
+ case QAbstractTexture::R16U:
+ return glImageFormatToGL(QShaderImage::R16U);
+ case QAbstractTexture::RG16U:
+ return glImageFormatToGL(QShaderImage::RG16U);
+ case QAbstractTexture::RGBA16U:
+ return glImageFormatToGL(QShaderImage::RGBA16U);
+
+ case QAbstractTexture::R32U:
+ return glImageFormatToGL(QShaderImage::R32U);
+ case QAbstractTexture::RG32U:
+ return glImageFormatToGL(QShaderImage::RG32U);
+ case QAbstractTexture::RGBA32U:
+ return glImageFormatToGL(QShaderImage::RGBA32U);
+
+ case QAbstractTexture::R8I:
+ return glImageFormatToGL(QShaderImage::R8I);
+ case QAbstractTexture::RG8I:
+ return glImageFormatToGL(QShaderImage::RG8I);
+ case QAbstractTexture::RGBA8I:
+ return glImageFormatToGL(QShaderImage::RGBA8I);
+
+ case QAbstractTexture::R16I:
+ return glImageFormatToGL(QShaderImage::R16I);
+ case QAbstractTexture::RG16I:
+ return glImageFormatToGL(QShaderImage::RG16I);
+ case QAbstractTexture::RGBA16I:
+ return glImageFormatToGL(QShaderImage::RGBA16I);
+
+ case QAbstractTexture::R32I:
+ return glImageFormatToGL(QShaderImage::R32I);
+ case QAbstractTexture::RG32I:
+ return glImageFormatToGL(QShaderImage::RG32I);
+ case QAbstractTexture::RGBA32I:
+ return glImageFormatToGL(QShaderImage::RGBA32I);
+
+ case QAbstractTexture::R16F:
+ return glImageFormatToGL(QShaderImage::R16F);
+ case QAbstractTexture::RG16F:
+ return glImageFormatToGL(QShaderImage::RG16F);
+ case QAbstractTexture::RGBA16F:
+ return glImageFormatToGL(QShaderImage::RGBA16F);
+
+ case QAbstractTexture::R32F:
+ return glImageFormatToGL(QShaderImage::R32F);
+ case QAbstractTexture::RG32F:
+ return glImageFormatToGL(QShaderImage::RG32F);
+ case QAbstractTexture::RGBA32F:
+ return glImageFormatToGL(QShaderImage::RGBA32F);
+
+ case QAbstractTexture::RG11B10F:
+ return glImageFormatToGL(QShaderImage::RG11B10F);
+ case QAbstractTexture::RGB10A2:
+ return glImageFormatToGL(QShaderImage::RGB10A2);
+ case QAbstractTexture::RGB10A2U:
+ return glImageFormatToGL(QShaderImage::RGB10A2U);
+
+ default:
+ qWarning() << "Cannot map Texture format" << textureFormat << "to a valid Image Format";
+ Q_UNREACHABLE();
+ return GL_NONE;
+ }
+}
+
+} // anonymous
+
+ImageSubmissionContext::ImageSubmissionContext()
+ : m_ctx(nullptr)
+{
+}
+
+void ImageSubmissionContext::initialize(GraphicsContext *context)
+{
+ m_ctx = context;
+ m_activeImages.resize(m_ctx->maxImageUnitsCount());
+}
+
+void ImageSubmissionContext::endDrawing()
+{
+ // Reduce score of all active Images
+ decayImageScores();
+}
+
+// Return Image Unit for Image
+// If Image was used previously and recently, it will return the last used unit
+// for that image. Otherwise it will try to return the image unit the least used.
+int ImageSubmissionContext::activateImage(ShaderImage *image, GLTexture *tex)
+{
+ const int onUnit = assignUnitForImage(image->peerId());
+
+ if (onUnit < 0) {
+ qWarning() << "Unable to find available image unit";
+ return -1;
+ }
+
+ QOpenGLTexture *glTex = tex->getGLTexture();
+ if (glTex == nullptr) {
+ qWarning() << "Unable to retrieve valid texture for Image";
+ return -1;
+ }
+
+ // Bind Image against Texture and resolve Image Format
+ m_ctx->bindImageTexture(onUnit,
+ glTex->textureId(),
+ image->mipLevel(),
+ image->layered(),
+ image->layer(),
+ glAccessEnumForShaderImageAccess(image->access()),
+ glImageFormatForShaderImageFormat(image->format(),
+ tex->properties().format));
+
+ // Store information about the Texture/Image on ActiveImage for given
+ // image unit
+ m_activeImages[onUnit].shaderImageId = image->peerId();
+ m_activeImages[onUnit].texture = tex;
+ m_activeImages[onUnit].score = 200;
+ m_activeImages[onUnit].pinned = true;
+
+ return onUnit;
+}
+
+// Unset pinned Active Image and reduce their score
+void ImageSubmissionContext::deactivateImages()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u) {
+ if (m_activeImages[u].pinned) {
+ m_activeImages[u].pinned = false;
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+ return;
+ }
+ }
+}
+
+// Reduce score of all active images (pinned or not)
+void ImageSubmissionContext::decayImageScores()
+{
+ for (int u = 0, m = m_activeImages.size(); u < m; ++u)
+ m_activeImages[u].score = qMax(m_activeImages[u].score - 1, 0);
+}
+
+int ImageSubmissionContext::assignUnitForImage(Qt3DCore::QNodeId shaderImageId)
+{
+ int lowestScoredUnit = -1;
+ int lowestScore = 0xfffffff;
+
+ const int m = m_activeImages.size();
+ for (int u = 0; u < m; ++u) {
+ if (m_activeImages[u].shaderImageId == shaderImageId)
+ return u;
+ }
+
+ for (int u = 0; u < m; ++u) {
+ // No image is currently active on the image unit
+ // we save the image unit with the texture that has been on there
+ // the longest time while not being used
+ if (!m_activeImages[u].pinned) {
+ const int score = m_activeImages[u].score;
+ if (score < lowestScore) {
+ lowestScore = score;
+ lowestScoredUnit = u;
+ }
+ }
+ }
+
+ if (lowestScoredUnit == -1)
+ qCWarning(Backend) << Q_FUNC_INFO << "No free image units!";
+
+ return lowestScoredUnit;
+}
+
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h b/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
new file mode 100644
index 000000000..6d39f469b
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/imagesubmissioncontext_p.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
+#define QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DCore/QNodeId>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+class ShaderImage;
+
+class Q_AUTOTEST_EXPORT ImageSubmissionContext
+{
+public:
+ ImageSubmissionContext();
+
+ void initialize(GraphicsContext *context);
+ void endDrawing();
+ int activateImage(ShaderImage *image, GLTexture *tex);
+ void deactivateImages();
+
+private:
+ void decayImageScores();
+ int assignUnitForImage(Qt3DCore::QNodeId shaderImageId);
+
+ struct ActiveImage
+ {
+ Qt3DCore::QNodeId shaderImageId;
+ GLTexture *texture = nullptr;
+ int score = 0;
+ bool pinned = false;
+ };
+ QVector<ActiveImage> m_activeImages;
+ GraphicsContext *m_ctx;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_IMAGESUBMISSIONCONTEXT_P_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/qgraphicsutils_p.h b/src/plugins/renderers/opengl/graphicshelpers/qgraphicsutils_p.h
new file mode 100644
index 000000000..efc952ea5
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/qgraphicsutils_p.h
@@ -0,0 +1,410 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_QGRAPHICSUTILS_P_H
+#define QT3DRENDER_RENDER_QGRAPHICSUTILS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/qt3drender_global.h>
+#include <QMatrix2x2>
+#include <QMatrix3x3>
+#include <QMatrix4x4>
+#include <QGenericMatrix>
+#include <QVector2D>
+#include <QVarLengthArray>
+#include <QColor>
+#include <shadervariables_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+namespace {
+
+const int QMatrix2x2Type = qMetaTypeId<QMatrix2x2>();
+const int QMatrix2x3Type = qMetaTypeId<QMatrix2x3>();
+const int QMatrix2x4Type = qMetaTypeId<QMatrix2x4>();
+const int QMatrix3x2Type = qMetaTypeId<QMatrix3x2>();
+const int QMatrix3x3Type = qMetaTypeId<QMatrix3x3>();
+const int QMatrix3x4Type = qMetaTypeId<QMatrix3x4>();
+const int QMatrix4x2Type = qMetaTypeId<QMatrix4x2>();
+const int QMatrix4x3Type = qMetaTypeId<QMatrix4x3>();
+
+}
+
+class QGraphicsUtils
+{
+
+public:
+
+ template<typename T>
+ static const char *bytesFromVariant(const QVariant &v)
+ {
+ uint byteSize = sizeof(T);
+ // Max 16 float that we may want as doubles
+ // 64 should be best for most cases
+ static QVarLengthArray<char, 64> array(16 * byteSize);
+ memset(array.data(), 0, array.size());
+
+ switch (static_cast<QMetaType::Type>(v.type())) {
+
+ // 1 byte
+ case QMetaType::Bool: {
+ T data = v.value<bool>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+ }
+ case QMetaType::Char: {
+ T data = v.value<char>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+ }
+
+ // 4 bytes
+ case QMetaType::Float: {
+ T data = v.value<float>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+ }
+ case QMetaType::Int: {
+ T data = v.value<int>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+
+ }
+ case QMetaType::UInt: {
+ qDebug() << "UINT";
+ T data = v.value<uint>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+ }
+
+ // 8 bytes
+ case QMetaType::Double: {
+ T data = v.value<double>();
+ memcpy(array.data(), &data, byteSize);
+ break;
+ }
+
+ // 2 floats
+ case QMetaType::QPointF: {
+ QPointF vv = v.value<QPointF>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ break;
+ }
+ case QMetaType::QSizeF: {
+ QSizeF vv = v.value<QSizeF>();
+ T data = vv.width();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.height();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ break;
+ }
+
+ case QMetaType::QVector2D: {
+ QVector2D vv = v.value<QVector2D>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ break;
+ }
+
+ // 2 ints
+ case QMetaType::QPoint: {
+ QPointF vv = v.value<QPoint>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ break;
+ }
+
+ case QMetaType::QSize: {
+ QSize vv = v.value<QSize>();
+ T data = vv.width();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.height();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ break;
+ }
+
+ // 3 floats
+ case QMetaType::QVector3D: {
+ QVector3D vv = v.value<QVector3D>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ data = vv.z();
+ memcpy(array.data() + 2 * byteSize, &data, byteSize);
+ break;
+ }
+
+ // 4 floats
+ case QMetaType::QVector4D: {
+ QVector4D vv = v.value<QVector4D>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ data = vv.z();
+ memcpy(array.data() + 2 * byteSize, &data, byteSize);
+ data = vv.w();
+ memcpy(array.data() + 3 * byteSize, &data, byteSize);
+ break;
+ }
+
+ case QMetaType::QQuaternion: {
+
+ break;
+ }
+
+ case QMetaType::QRectF: {
+ QRectF vv = v.value<QRectF>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ data = vv.width();
+ memcpy(array.data() + 2 * byteSize, &data, byteSize);
+ data = vv.height();
+ memcpy(array.data() + 3 * byteSize, &data, byteSize);
+ break;
+ }
+
+ case QMetaType::QColor: {
+ QColor vv = v.value<QColor>();
+ T data = vv.redF();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.greenF();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ data = vv.blueF();
+ memcpy(array.data() + 2 * byteSize, &data, byteSize);
+ data = vv.alphaF();
+ memcpy(array.data() + 3 * byteSize, &data, byteSize);
+ break;
+ }
+
+ // 4 ints
+ case QMetaType::QRect: {
+ QRectF vv = v.value<QRect>();
+ T data = vv.x();
+ memcpy(array.data(), &data, byteSize);
+ data = vv.y();
+ memcpy(array.data() + byteSize, &data, byteSize);
+ data = vv.width();
+ memcpy(array.data() + 2 * byteSize, &data, byteSize);
+ data = vv.height();
+ memcpy(array.data() + 3 * byteSize, &data, byteSize);
+ break;
+ }
+
+ // 16 floats
+ case QMetaType::QMatrix4x4: {
+ QMatrix4x4 mat = v.value<QMatrix4x4>();
+ float *data = mat.data();
+ for (int i = 0; i < 16; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ break;
+ }
+
+ default: {
+
+ float *data = nullptr;
+ if (v.userType() == QMatrix3x3Type) {
+ QMatrix3x3 mat = v.value<QMatrix3x3>();
+ data = mat.data();
+ for (int i = 0; i < 9; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix2x2Type) {
+ QMatrix2x2 mat = v.value<QMatrix2x2>();
+ data = mat.data();
+ for (int i = 0; i < 4; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix2x3Type) {
+ QMatrix2x3 mat = v.value<QMatrix2x3>();
+ data = mat.data();
+ for (int i = 0; i < 6; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix3x2Type) {
+ QMatrix3x2 mat = v.value<QMatrix3x2>();
+ data = mat.data();
+ for (int i = 0; i < 6; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix2x4Type) {
+ QMatrix2x4 mat = v.value<QMatrix2x4>();
+ data = mat.data();
+ for (int i = 0; i < 8; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix4x2Type) {
+ QMatrix4x2 mat = v.value<QMatrix4x2>();
+ data = mat.data();
+ for (int i = 0; i < 8; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix3x4Type) {
+ QMatrix3x4 mat = v.value<QMatrix3x4>();
+ data = mat.data();
+ for (int i = 0; i < 12; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else if (v.userType() == QMatrix4x3Type) {
+ QMatrix4x3 mat = v.value<QMatrix4x3>();
+ data = mat.data();
+ for (int i = 0; i < 12; i++) {
+ T d = data[i];
+ memcpy(array.data() + i * byteSize, &d, byteSize);
+ }
+ }
+ else
+ qWarning() << Q_FUNC_INFO << "QVariant type conversion not handled for " << v.type();
+ break;
+ }
+
+ }
+ return array.constData();
+ }
+
+
+ template<typename T>
+ static const T *valueArrayFromVariant(const QVariant &v, int count, int tupleSize)
+ {
+ uint byteSize = sizeof(T);
+ uint offset = byteSize * tupleSize;
+ static QVarLengthArray<char, 1024> uniformValuesArray(1024);
+ uniformValuesArray.resize(count * offset);
+ char *data = uniformValuesArray.data();
+ memset(data, 0, uniformValuesArray.size());
+
+ QVariantList vList = v.toList();
+ // Handles list of QVariant: usually arrays of float
+ if (!vList.isEmpty()) {
+ for (int i = 0; i < vList.length() && uint(i) * offset < uint(uniformValuesArray.size()); i++) {
+ const char *subBuffer = QGraphicsUtils::bytesFromVariant<T>(vList.at(i));
+ memcpy(data + i * offset, subBuffer, offset);
+ }
+ }
+ else {
+ memcpy(data, QGraphicsUtils::bytesFromVariant<T>(v), offset);
+ }
+ return reinterpret_cast<const T *>(uniformValuesArray.constData());
+ }
+
+ template<typename T>
+ static void fillDataArray(void *buffer, const T *data, const ShaderUniform &description, int tupleSize)
+ {
+ uint offset = description.m_offset / sizeof(T);
+ uint stride = description.m_arrayStride / sizeof(T);
+ T *bufferData = (T*)buffer;
+
+ for (int i = 0; i < description.m_size; ++i) {
+ for (int j = 0; j < tupleSize; j++) {
+ int idx = i * tupleSize + j;
+ bufferData[offset + j] = data[idx];
+ }
+ offset += stride;
+ }
+ }
+
+ template<typename T>
+ static void fillDataMatrixArray(void *buffer, const T *data, const ShaderUniform &description, int cols, int rows)
+ {
+ uint offset = description.m_offset / sizeof(T);
+ uint arrayStride = description.m_arrayStride / sizeof(T);
+ uint matrixStride = description.m_matrixStride / sizeof(T);
+ T *bufferData = (T*)buffer;
+
+ for (int i = 0; i < description.m_size; ++i) {
+ for (int col = 0; col < cols; ++col) {
+ for (int row = 0; row < rows; ++row) {
+ int idx = i * cols * rows + rows * col + row;
+ bufferData[offset + row] = data[idx];
+ }
+ offset += matrixStride;
+ }
+ offset += arrayStride;
+ }
+ }
+
+};
+
+} // namespace Render
+
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_QGRAPHICSUTILS_P_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp
new file mode 100644
index 000000000..9501b0b52
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext.cpp
@@ -0,0 +1,1574 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "submissioncontext_p.h"
+
+#include <Qt3DRender/qgraphicsapifilter.h>
+#include <Qt3DRender/qparameter.h>
+#include <Qt3DRender/qcullface.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/renderstates_p.h>
+#include <Qt3DRender/private/renderstateset_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/stringtoint_p.h>
+#include <gltexture_p.h>
+#include <rendercommand_p.h>
+#include <graphicshelperinterface_p.h>
+#include <renderer_p.h>
+#include <glresourcemanagers_p.h>
+#include <renderbuffer_p.h>
+#include <glshader_p.h>
+#include <openglvertexarrayobject_p.h>
+#include <QOpenGLShaderProgram>
+
+#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 <private/qdebug_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
+
+namespace Qt3DRender {
+namespace Render {
+
+
+static QHash<unsigned int, SubmissionContext*> static_contexts;
+
+unsigned int nextFreeContextId()
+{
+ for (unsigned int i=0; i < 0xffff; ++i) {
+ if (!static_contexts.contains(i))
+ return i;
+ }
+
+ qFatal("Couldn't find free context ID");
+ return 0;
+}
+
+namespace {
+
+GLBuffer::Type attributeTypeToGLBufferType(QAttribute::AttributeType type)
+{
+ switch (type) {
+ case QAttribute::VertexAttribute:
+ return GLBuffer::ArrayBuffer;
+ case QAttribute::IndexAttribute:
+ return GLBuffer::IndexBuffer;
+ case QAttribute::DrawIndirectAttribute:
+ return GLBuffer::DrawIndirectBuffer;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void copyGLFramebufferDataToImage(QImage &img, const uchar *srcData, uint stride, uint width, uint height, QAbstractTexture::TextureFormat format)
+{
+ switch (format) {
+ case QAbstractTexture::RGBA32F:
+ {
+ uchar *srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ uchar *dstScanline = img.scanLine(i);
+ float *pSrc = (float*)srcScanline;
+ for (uint j = 0; j < width; j++) {
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+2], 1.0f));
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+1], 1.0f));
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+0], 1.0f));
+ *dstScanline++ = (uchar)(255.0f * qBound(0.0f, pSrc[4*j+3], 1.0f));
+ }
+ srcScanline -= stride;
+ }
+ } break;
+ default:
+ {
+ uchar* srcScanline = (uchar *)srcData + stride * (height - 1);
+ for (uint i = 0; i < height; ++i) {
+ memcpy(img.scanLine(i), srcScanline, stride);
+ srcScanline -= stride;
+ }
+ } break;
+ }
+}
+
+// Render States Helpers
+template<typename GenericState>
+void applyStateHelper(const GenericState *state, SubmissionContext *gc)
+{
+ Q_UNUSED(state);
+ Q_UNUSED(gc);
+}
+
+template<>
+void applyStateHelper<AlphaFunc>(const AlphaFunc *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->alphaTest(std::get<0>(values), std::get<1>(values));
+}
+
+template<>
+void applyStateHelper<BlendEquationArguments>(const BlendEquationArguments *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ // Un-indexed BlendEquationArguments -> Use normal GL1.0 functions
+ if (std::get<5>(values) < 0) {
+ if (std::get<4>(values)) {
+ gc->openGLContext()->functions()->glEnable(GL_BLEND);
+ gc->openGLContext()->functions()->glBlendFuncSeparate(std::get<0>(values), std::get<1>(values), std::get<2>(values), std::get<3>(values));
+ } else {
+ gc->openGLContext()->functions()->glDisable(GL_BLEND);
+ }
+ }
+ // BlendEquationArguments for a particular Draw Buffer. Different behaviours for
+ // (1) 3.0-3.3: only enablei/disablei supported.
+ // (2) 4.0+: all operations supported.
+ // We just ignore blend func parameter for (1), so no warnings get
+ // printed.
+ else {
+ if (std::get<4>(values)) {
+ gc->enablei(GL_BLEND, std::get<5>(values));
+ if (gc->supportsDrawBuffersBlend()) {
+ gc->blendFuncSeparatei(std::get<5>(values), std::get<0>(values), std::get<1>(values), std::get<2>(values), std::get<3>(values));
+ }
+ } else {
+ gc->disablei(GL_BLEND, std::get<5>(values));
+ }
+ }
+}
+
+template<>
+void applyStateHelper<BlendEquation>(const BlendEquation *state, SubmissionContext *gc)
+{
+ gc->blendEquation(std::get<0>(state->values()));
+}
+
+template<>
+void applyStateHelper<MSAAEnabled>(const MSAAEnabled *state, SubmissionContext *gc)
+{
+ gc->setMSAAEnabled(std::get<0>(state->values()));
+}
+
+template<>
+void applyStateHelper<DepthRange>(const DepthRange *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->depthRange(std::get<0>(values), std::get<1>(values));
+}
+
+template<>
+void applyStateHelper<DepthTest>(const DepthTest *state, SubmissionContext *gc)
+{
+ gc->depthTest(std::get<0>(state->values()));
+}
+
+template<>
+void applyStateHelper<RasterMode>(const RasterMode *state, SubmissionContext *gc)
+{
+ gc->rasterMode(std::get<0>(state->values()), std::get<1>(state->values()));
+}
+
+template<>
+void applyStateHelper<NoDepthMask>(const NoDepthMask *state, SubmissionContext *gc)
+{
+ gc->depthMask(std::get<0>(state->values()));
+}
+
+template<>
+void applyStateHelper<CullFace>(const CullFace *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ if (std::get<0>(values) == QCullFace::NoCulling) {
+ gc->openGLContext()->functions()->glDisable(GL_CULL_FACE);
+ } else {
+ gc->openGLContext()->functions()->glEnable(GL_CULL_FACE);
+ gc->openGLContext()->functions()->glCullFace(std::get<0>(values));
+ }
+}
+
+template<>
+void applyStateHelper<FrontFace>(const FrontFace *state, SubmissionContext *gc)
+{
+ gc->frontFace(std::get<0>(state->values()));
+}
+
+template<>
+void applyStateHelper<ScissorTest>(const ScissorTest *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glEnable(GL_SCISSOR_TEST);
+ gc->openGLContext()->functions()->glScissor(std::get<0>(values), std::get<1>(values), std::get<2>(values), std::get<3>(values));
+}
+
+template<>
+void applyStateHelper<StencilTest>(const StencilTest *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glEnable(GL_STENCIL_TEST);
+ gc->openGLContext()->functions()->glStencilFuncSeparate(GL_FRONT, std::get<0>(values), std::get<1>(values), std::get<2>(values));
+ gc->openGLContext()->functions()->glStencilFuncSeparate(GL_BACK, std::get<3>(values), std::get<4>(values), std::get<5>(values));
+}
+
+template<>
+void applyStateHelper<AlphaCoverage>(const AlphaCoverage *, SubmissionContext *gc)
+{
+ gc->setAlphaCoverageEnabled(true);
+}
+
+template<>
+void applyStateHelper<PointSize>(const PointSize *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->pointSize(std::get<0>(values), std::get<1>(values));
+}
+
+
+template<>
+void applyStateHelper<PolygonOffset>(const PolygonOffset *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glEnable(GL_POLYGON_OFFSET_FILL);
+ gc->openGLContext()->functions()->glPolygonOffset(std::get<0>(values), std::get<1>(values));
+}
+
+template<>
+void applyStateHelper<ColorMask>(const ColorMask *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glColorMask(std::get<0>(values), std::get<1>(values), std::get<2>(values), std::get<3>(values));
+}
+
+template<>
+void applyStateHelper<ClipPlane>(const ClipPlane *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->enableClipPlane(std::get<0>(values));
+ gc->setClipPlane(std::get<0>(values), std::get<1>(values), std::get<2>(values));
+}
+
+template<>
+void applyStateHelper<SeamlessCubemap>(const SeamlessCubemap *, SubmissionContext *gc)
+{
+ gc->setSeamlessCubemap(true);
+}
+
+template<>
+void applyStateHelper<StencilOp>(const StencilOp *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glStencilOpSeparate(GL_FRONT, std::get<0>(values), std::get<1>(values), std::get<2>(values));
+ gc->openGLContext()->functions()->glStencilOpSeparate(GL_BACK, std::get<3>(values), std::get<4>(values), std::get<5>(values));
+}
+
+template<>
+void applyStateHelper<StencilMask>(const StencilMask *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ gc->openGLContext()->functions()->glStencilMaskSeparate(GL_FRONT, std::get<0>(values));
+ gc->openGLContext()->functions()->glStencilMaskSeparate(GL_BACK, std::get<1>(values));
+}
+
+template<>
+void applyStateHelper<Dithering>(const Dithering *, SubmissionContext *gc)
+{
+ gc->openGLContext()->functions()->glEnable(GL_DITHER);
+}
+
+#ifndef GL_LINE_SMOOTH
+#define GL_LINE_SMOOTH 0x0B20
+#endif
+
+template<>
+void applyStateHelper<LineWidth>(const LineWidth *state, SubmissionContext *gc)
+{
+ const auto values = state->values();
+ if (std::get<1>(values))
+ gc->openGLContext()->functions()->glEnable(GL_LINE_SMOOTH);
+ else
+ gc->openGLContext()->functions()->glDisable(GL_LINE_SMOOTH);
+
+ gc->openGLContext()->functions()->glLineWidth(std::get<0>(values));
+}
+
+} // anonymous
+
+
+SubmissionContext::SubmissionContext()
+ : GraphicsContext()
+ , m_ownCurrent(true)
+ , m_id(nextFreeContextId())
+ , m_surface(nullptr)
+ , m_activeShader(nullptr)
+ , m_renderTargetFormat(QAbstractTexture::NoFormat)
+ , m_currClearStencilValue(0)
+ , m_currClearDepthValue(1.f)
+ , m_currClearColorValue(0,0,0,0)
+ , m_material(nullptr)
+ , m_activeFBO(0)
+ , m_boundArrayBuffer(nullptr)
+ , m_stateSet(nullptr)
+ , m_renderer(nullptr)
+ , m_uboTempArray(QByteArray(1024, 0))
+{
+ static_contexts[m_id] = this;
+}
+
+SubmissionContext::~SubmissionContext()
+{
+ releaseOpenGL();
+
+ Q_ASSERT(static_contexts[m_id] == this);
+ static_contexts.remove(m_id);
+}
+
+void SubmissionContext::initialize()
+{
+ GraphicsContext::initialize();
+ m_textureContext.initialize(this);
+ m_imageContext.initialize(this);
+}
+
+void SubmissionContext::resolveRenderTargetFormat()
+{
+ const QSurfaceFormat format = m_gl->format();
+ const uint a = (format.alphaBufferSize() == -1) ? 0 : format.alphaBufferSize();
+ const uint r = format.redBufferSize();
+ const uint g = format.greenBufferSize();
+ const uint b = format.blueBufferSize();
+
+#define RGBA_BITS(r,g,b,a) (r | (g << 6) | (b << 12) | (a << 18))
+
+ const uint bits = RGBA_BITS(r,g,b,a);
+ switch (bits) {
+ case RGBA_BITS(8,8,8,8):
+ m_renderTargetFormat = QAbstractTexture::RGBA8_UNorm;
+ break;
+ case RGBA_BITS(8,8,8,0):
+ m_renderTargetFormat = QAbstractTexture::RGB8_UNorm;
+ break;
+ case RGBA_BITS(5,6,5,0):
+ m_renderTargetFormat = QAbstractTexture::R5G6B5;
+ break;
+ }
+#undef RGBA_BITS
+}
+
+bool SubmissionContext::beginDrawing(QSurface *surface)
+{
+ Q_ASSERT(surface);
+ Q_ASSERT(m_gl);
+
+ m_surface = surface;
+
+ // TO DO: Find a way to make to pause work if the window is not exposed
+ // if (m_surface && m_surface->surfaceClass() == QSurface::Window) {
+ // qDebug() << Q_FUNC_INFO << 1;
+ // if (!static_cast<QWindow *>(m_surface)->isExposed())
+ // return false;
+ // qDebug() << Q_FUNC_INFO << 2;
+ // }
+
+ // Makes the surface current on the OpenGLContext
+ // and sets the right glHelper
+ m_ownCurrent = !(m_gl->surface() == m_surface);
+ if (m_ownCurrent && !makeCurrent(m_surface))
+ return false;
+
+ // TODO: cache surface format somewhere rather than doing this every time render surface changes
+ resolveRenderTargetFormat();
+
+#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
+ GLint err = m_gl->functions()->glGetError();
+ if (err != 0) {
+ qCWarning(Backend) << Q_FUNC_INFO << "glGetError:" << err;
+ }
+#endif
+
+ if (!isInitialized())
+ initialize();
+ initializeHelpers(m_surface);
+
+ // need to reset these values every frame, may get overwritten elsewhere
+ m_gl->functions()->glClearColor(m_currClearColorValue.redF(), m_currClearColorValue.greenF(), m_currClearColorValue.blueF(), m_currClearColorValue.alphaF());
+ m_gl->functions()->glClearDepthf(m_currClearDepthValue);
+ m_gl->functions()->glClearStencil(m_currClearStencilValue);
+
+ if (m_activeShader) {
+ m_activeShader = nullptr;
+ }
+
+ m_boundArrayBuffer = nullptr;
+ return true;
+}
+
+void SubmissionContext::endDrawing(bool swapBuffers)
+{
+ if (swapBuffers)
+ m_gl->swapBuffers(m_surface);
+ if (m_ownCurrent)
+ m_gl->doneCurrent();
+ m_textureContext.endDrawing();
+ m_imageContext.endDrawing();
+}
+
+void SubmissionContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, GLuint defaultFboId)
+{
+ GLuint fboId = defaultFboId; // Default FBO
+ if (renderTargetNodeId) {
+ // New RenderTarget
+ if (!m_renderTargets.contains(renderTargetNodeId)) {
+ if (m_defaultFBO && fboId == m_defaultFBO) {
+ // this is the default fbo that some platforms create (iOS), we just register it
+ // Insert FBO into hash
+ m_renderTargets.insert(renderTargetNodeId, fboId);
+ } else {
+ fboId = createRenderTarget(renderTargetNodeId, attachments);
+ }
+ } else {
+ fboId = updateRenderTarget(renderTargetNodeId, attachments, true);
+ }
+ }
+ m_activeFBO = fboId;
+ m_glHelper->bindFrameBufferObject(m_activeFBO, GraphicsHelperInterface::FBODraw);
+ // Set active drawBuffers
+ activateDrawBuffers(attachments);
+}
+
+GLuint SubmissionContext::createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments)
+{
+ const GLuint fboId = m_glHelper->createFrameBufferObject();
+ if (fboId) {
+ // The FBO is created and its attachments are set once
+ // Insert FBO into hash
+ m_renderTargets.insert(renderTargetNodeId, fboId);
+ // Bind FBO
+ m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw);
+ bindFrameBufferAttachmentHelper(fboId, attachments);
+ } else {
+ qCritical("Failed to create FBO");
+ }
+ return fboId;
+}
+
+GLuint SubmissionContext::updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, bool isActiveRenderTarget)
+{
+ const GLuint fboId = m_renderTargets.value(renderTargetNodeId);
+
+ // We need to check if one of the attachment was resized
+ bool needsResize = !m_renderTargetsSize.contains(fboId); // not even initialized yet?
+ if (!needsResize) {
+ // render target exists, has attachment been resized?
+ GLTextureManager *glTextureManager = m_renderer->glResourceManagers()->glTextureManager();
+ const QSize s = m_renderTargetsSize[fboId];
+ const auto attachments_ = attachments.attachments();
+ for (const Attachment &attachment : attachments_) {
+ GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid);
+ // ### TODO QTBUG-64757 this check is insufficient since the
+ // texture may have changed to another one with the same size. That
+ // case is not handled atm.
+ if (rTex) {
+ needsResize |= rTex->size() != s;
+ if (isActiveRenderTarget && attachment.m_point == QRenderTargetOutput::Color0)
+ m_renderTargetFormat = rTex->properties().format;
+ }
+ }
+ }
+
+ if (needsResize) {
+ m_glHelper->bindFrameBufferObject(fboId, GraphicsHelperInterface::FBODraw);
+ bindFrameBufferAttachmentHelper(fboId, attachments);
+ }
+
+ return fboId;
+}
+
+QSize SubmissionContext::renderTargetSize(const QSize &surfaceSize) const
+{
+ QSize renderTargetSize;
+ if (m_activeFBO != m_defaultFBO) {
+ // For external FBOs we may not have a m_renderTargets entry.
+ if (m_renderTargetsSize.contains(m_activeFBO)) {
+ renderTargetSize = m_renderTargetsSize[m_activeFBO];
+ } else if (surfaceSize.isValid()) {
+ renderTargetSize = surfaceSize;
+ } else {
+ // External FBO (when used with QtQuick2 Scene3D)
+
+ // Query FBO color attachment 0 size
+ GLint attachmentObjectType = GL_NONE;
+ GLint attachment0Name = 0;
+ m_gl->functions()->glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ &attachmentObjectType);
+ m_gl->functions()->glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ &attachment0Name);
+
+ if (attachmentObjectType == GL_RENDERBUFFER && m_glHelper->supportsFeature(GraphicsHelperInterface::RenderBufferDimensionRetrieval))
+ renderTargetSize = m_glHelper->getRenderBufferDimensions(attachment0Name);
+ else if (attachmentObjectType == GL_TEXTURE && m_glHelper->supportsFeature(GraphicsHelperInterface::TextureDimensionRetrieval))
+ // Assumes texture level 0 and GL_TEXTURE_2D target
+ renderTargetSize = m_glHelper->getTextureDimensions(attachment0Name, GL_TEXTURE_2D);
+ else
+ return renderTargetSize;
+ }
+ } else {
+ renderTargetSize = m_surface->size();
+ if (m_surface->surfaceClass() == QSurface::Window) {
+ const float dpr = static_cast<QWindow *>(m_surface)->devicePixelRatio();
+ renderTargetSize *= dpr;
+ }
+ }
+ return renderTargetSize;
+}
+
+QImage SubmissionContext::readFramebuffer(const QRect &rect)
+{
+ QImage img;
+ const unsigned int area = rect.width() * rect.height();
+ unsigned int bytes;
+ GLenum format, type;
+ QImage::Format imageFormat;
+ uint stride;
+
+ /* format value should match GL internalFormat */
+ GLenum internalFormat = m_renderTargetFormat;
+
+ switch (m_renderTargetFormat) {
+ case QAbstractTexture::RGBAFormat:
+ case QAbstractTexture::RGBA8_SNorm:
+ case QAbstractTexture::RGBA8_UNorm:
+ case QAbstractTexture::RGBA8U:
+ case QAbstractTexture::SRGB8_Alpha8:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBA8888_Premultiplied;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ internalFormat = GL_RGBA8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = rect.width() * 4;
+ break;
+ case QAbstractTexture::SRGB8:
+ case QAbstractTexture::RGBFormat:
+ case QAbstractTexture::RGB8U:
+ case QAbstractTexture::RGB8_UNorm:
+#ifdef QT_OPENGL_ES_2
+ format = GL_RGBA;
+ imageFormat = QImage::Format_RGBX8888;
+#else
+ format = GL_BGRA;
+ imageFormat = QImage::Format_RGB32;
+ internalFormat = GL_RGB8;
+#endif
+ type = GL_UNSIGNED_BYTE;
+ bytes = area * 4;
+ stride = rect.width() * 4;
+ break;
+#ifndef QT_OPENGL_ES_2
+ case QAbstractTexture::RG11B10F:
+ bytes = area * 4;
+ format = GL_RGB;
+ type = GL_UNSIGNED_INT_10F_11F_11F_REV;
+ imageFormat = QImage::Format_RGB30;
+ stride = rect.width() * 4;
+ break;
+ case QAbstractTexture::RGB10A2:
+ bytes = area * 4;
+ format = GL_RGBA;
+ type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ imageFormat = QImage::Format_A2BGR30_Premultiplied;
+ stride = rect.width() * 4;
+ break;
+ case QAbstractTexture::R5G6B5:
+ bytes = area * 2;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT;
+ internalFormat = GL_UNSIGNED_SHORT_5_6_5_REV;
+ imageFormat = QImage::Format_RGB16;
+ stride = rect.width() * 2;
+ break;
+ case QAbstractTexture::RGBA16F:
+ case QAbstractTexture::RGBA16U:
+ case QAbstractTexture::RGBA32F:
+ case QAbstractTexture::RGBA32U:
+ bytes = area * 16;
+ format = GL_RGBA;
+ type = GL_FLOAT;
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+ stride = rect.width() * 16;
+ break;
+#endif
+ default:
+ auto warning = qWarning();
+ warning << "Unable to convert";
+ QtDebugUtils::formatQEnum(warning, m_renderTargetFormat);
+ warning << "render target texture format to QImage.";
+ return img;
+ }
+
+ GLint samples = 0;
+ m_gl->functions()->glGetIntegerv(GL_SAMPLES, &samples);
+ if (samples > 0 && !m_glHelper->supportsFeature(GraphicsHelperInterface::BlitFramebuffer)) {
+ qCWarning(Backend) << Q_FUNC_INFO << "Unable to capture multisampled framebuffer; "
+ "Required feature BlitFramebuffer is missing.";
+ return img;
+ }
+
+ img = QImage(rect.width(), rect.height(), imageFormat);
+
+ QScopedArrayPointer<uchar> data(new uchar [bytes]);
+
+ if (samples > 0) {
+ // resolve multisample-framebuffer to renderbuffer and read pixels from it
+ GLuint fbo, rb;
+ QOpenGLFunctions *gl = m_gl->functions();
+ gl->glGenFramebuffers(1, &fbo);
+ gl->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+ gl->glGenRenderbuffers(1, &rb);
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glRenderbufferStorage(GL_RENDERBUFFER, internalFormat, rect.width(), rect.height());
+ gl->glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rb);
+
+ const GLenum status = gl->glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glDeleteFramebuffers(1, &fbo);
+ qCWarning(Backend) << Q_FUNC_INFO << "Copy-framebuffer not complete: " << status;
+ return img;
+ }
+
+ m_glHelper->blitFramebuffer(rect.x(), rect.y(), rect.x() + rect.width(), rect.y() + rect.height(),
+ 0, 0, rect.width(), rect.height(),
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ gl->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
+ gl->glReadPixels(0,0,rect.width(), rect.height(), format, type, data.data());
+
+ copyGLFramebufferDataToImage(img, data.data(), stride, rect.width(), rect.height(), m_renderTargetFormat);
+
+ gl->glBindRenderbuffer(GL_RENDERBUFFER, rb);
+ gl->glDeleteRenderbuffers(1, &rb);
+ gl->glBindFramebuffer(GL_FRAMEBUFFER, m_activeFBO);
+ gl->glDeleteFramebuffers(1, &fbo);
+ } else {
+ // read pixels directly from framebuffer
+ m_gl->functions()->glReadPixels(rect.x(), rect.y(), rect.width(), rect.height(), format, type, data.data());
+ copyGLFramebufferDataToImage(img, data.data(), stride, rect.width(), rect.height(), m_renderTargetFormat);
+ }
+
+ return img;
+}
+
+void SubmissionContext::setViewport(const QRectF &viewport, const QSize &surfaceSize)
+{
+ // // save for later use; this has nothing to do with the viewport but it is
+ // // here that we get to know the surfaceSize from the RenderView.
+ m_surfaceSize = surfaceSize;
+
+ m_viewport = viewport;
+ QSize size = renderTargetSize(surfaceSize);
+
+ // Check that the returned size is before calling glViewport
+ if (size.isEmpty())
+ return;
+
+ // Qt3D 0------------------> 1 OpenGL 1^
+ // | |
+ // | |
+ // | |
+ // V |
+ // 1 0---------------------> 1
+ // The Viewport is defined between 0 and 1 which allows us to automatically
+ // scale to the size of the provided window surface
+ m_gl->functions()->glViewport(m_viewport.x() * size.width(),
+ (1.0 - m_viewport.y() - m_viewport.height()) * size.height(),
+ m_viewport.width() * size.width(),
+ m_viewport.height() * size.height());
+}
+
+void SubmissionContext::releaseOpenGL()
+{
+ m_renderBufferHash.clear();
+
+ // Stop and destroy the OpenGL logger
+ if (m_debugLogger) {
+ m_debugLogger->stopLogging();
+ m_debugLogger.reset(nullptr);
+ }
+}
+
+// The OpenGLContext is not current on any surface at this point
+void SubmissionContext::setOpenGLContext(QOpenGLContext* ctx)
+{
+ Q_ASSERT(ctx);
+
+ releaseOpenGL();
+ m_gl = ctx;
+}
+
+// Called only from RenderThread
+bool SubmissionContext::activateShader(GLShader *shader)
+{
+ if (shader->shaderProgram() != m_activeShader) {
+ // Ensure material uniforms are re-applied
+ m_material = nullptr;
+
+ m_activeShader = shader->shaderProgram();
+ if (Q_LIKELY(m_activeShader != nullptr)) {
+ m_activeShader->bind();
+ } else {
+ m_glHelper->useProgram(0);
+ qWarning() << "No shader program found";
+ return false;
+ }
+ }
+ return true;
+}
+
+void SubmissionContext::bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments)
+{
+ // Set FBO attachments. These are normally textures, except that on Open GL
+ // ES <= 3.1 we must use a renderbuffer if a combined depth+stencil is
+ // desired since this cannot be achieved neither with a single texture (not
+ // before GLES 3.2) nor with separate textures (no suitable format for
+ // stencil before 3.1 with the appropriate extension).
+
+ QSize fboSize;
+ GLTextureManager *glTextureManager = m_renderer->glResourceManagers()->glTextureManager();
+ const auto attachments_ = attachments.attachments();
+ for (const Attachment &attachment : attachments_) {
+ GLTexture *rTex = glTextureManager->lookupResource(attachment.m_textureUuid);
+ if (!m_glHelper->frameBufferNeedsRenderBuffer(attachment)) {
+ QOpenGLTexture *glTex = rTex ? rTex->getGLTexture() : nullptr;
+ if (glTex != nullptr) {
+ // The texture can not be rendered simultaniously by another renderer
+ Q_ASSERT(!rTex->isExternalRenderingEnabled());
+ if (fboSize.isEmpty())
+ fboSize = QSize(glTex->width(), glTex->height());
+ else
+ fboSize = QSize(qMin(fboSize.width(), glTex->width()), qMin(fboSize.height(), glTex->height()));
+ m_glHelper->bindFrameBufferAttachment(glTex, attachment);
+ }
+ } else {
+ RenderBuffer *renderBuffer = rTex ? rTex->getOrCreateRenderBuffer() : nullptr;
+ if (renderBuffer) {
+ if (fboSize.isEmpty())
+ fboSize = QSize(renderBuffer->width(), renderBuffer->height());
+ else
+ fboSize = QSize(qMin(fboSize.width(), renderBuffer->width()), qMin(fboSize.height(), renderBuffer->height()));
+ m_glHelper->bindFrameBufferAttachment(renderBuffer, attachment);
+ }
+ }
+ }
+ m_renderTargetsSize.insert(fboId, fboSize);
+}
+
+void SubmissionContext::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 {
+ qCWarning(Backend) << "FBO incomplete";
+ }
+}
+
+
+void SubmissionContext::setActiveMaterial(Material *rmat)
+{
+ if (m_material == rmat)
+ return;
+
+ m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial);
+ m_imageContext.deactivateImages();
+ m_material = rmat;
+}
+
+void SubmissionContext::setCurrentStateSet(RenderStateSet *ss)
+{
+ if (ss == m_stateSet)
+ return;
+ if (ss)
+ applyStateSet(ss);
+ m_stateSet = ss;
+}
+
+RenderStateSet *SubmissionContext::currentStateSet() const
+{
+ return m_stateSet;
+}
+
+void SubmissionContext::applyState(const StateVariant &stateVariant)
+{
+ switch (stateVariant.type) {
+
+ case AlphaCoverageStateMask: {
+ applyStateHelper<AlphaCoverage>(static_cast<const AlphaCoverage *>(stateVariant.constState()), this);
+ break;
+ }
+ case AlphaTestMask: {
+ applyStateHelper<AlphaFunc>(static_cast<const AlphaFunc *>(stateVariant.constState()), this);
+ break;
+ }
+ case BlendStateMask: {
+ applyStateHelper<BlendEquation>(static_cast<const BlendEquation *>(stateVariant.constState()), this);
+ break;
+ }
+ case BlendEquationArgumentsMask: {
+ applyStateHelper<BlendEquationArguments>(static_cast<const BlendEquationArguments *>(stateVariant.constState()), this);
+ break;
+ }
+ case MSAAEnabledStateMask: {
+ applyStateHelper<MSAAEnabled>(static_cast<const MSAAEnabled *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case CullFaceStateMask: {
+ applyStateHelper<CullFace>(static_cast<const CullFace *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case DepthWriteStateMask: {
+ applyStateHelper<NoDepthMask>(static_cast<const NoDepthMask *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case DepthTestStateMask: {
+ applyStateHelper<DepthTest>(static_cast<const DepthTest *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case DepthRangeMask: {
+ applyStateHelper<DepthRange>(static_cast<const DepthRange *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case RasterModeMask: {
+ applyStateHelper<RasterMode>(static_cast<const RasterMode *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case FrontFaceStateMask: {
+ applyStateHelper<FrontFace>(static_cast<const FrontFace *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case ScissorStateMask: {
+ applyStateHelper<ScissorTest>(static_cast<const ScissorTest *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case StencilTestStateMask: {
+ applyStateHelper<StencilTest>(static_cast<const StencilTest *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case PointSizeMask: {
+ applyStateHelper<PointSize>(static_cast<const PointSize *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case PolygonOffsetStateMask: {
+ applyStateHelper<PolygonOffset>(static_cast<const PolygonOffset *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case ColorStateMask: {
+ applyStateHelper<ColorMask>(static_cast<const ColorMask *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case ClipPlaneMask: {
+ applyStateHelper<ClipPlane>(static_cast<const ClipPlane *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case SeamlessCubemapMask: {
+ applyStateHelper<SeamlessCubemap>(static_cast<const SeamlessCubemap *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case StencilOpMask: {
+ applyStateHelper<StencilOp>(static_cast<const StencilOp *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case StencilWriteStateMask: {
+ applyStateHelper<StencilMask>(static_cast<const StencilMask *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case DitheringStateMask: {
+ applyStateHelper<Dithering>(static_cast<const Dithering *>(stateVariant.constState()), this);
+ break;
+ }
+
+ case LineWidthMask: {
+ applyStateHelper<LineWidth>(static_cast<const LineWidth *>(stateVariant.constState()), this);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void SubmissionContext::resetMasked(qint64 maskOfStatesToReset)
+{
+ // TO DO -> Call gcHelper methods instead of raw GL
+ // QOpenGLFunctions shouldn't be used here directly
+ QOpenGLFunctions *funcs = m_gl->functions();
+
+ if (maskOfStatesToReset & ScissorStateMask)
+ funcs->glDisable(GL_SCISSOR_TEST);
+
+ if (maskOfStatesToReset & BlendStateMask)
+ funcs->glDisable(GL_BLEND);
+
+ if (maskOfStatesToReset & StencilWriteStateMask)
+ funcs->glStencilMask(0);
+
+ if (maskOfStatesToReset & StencilTestStateMask)
+ funcs->glDisable(GL_STENCIL_TEST);
+
+ if (maskOfStatesToReset & DepthRangeMask)
+ depthRange(0.0f, 1.0f);
+
+ if (maskOfStatesToReset & DepthTestStateMask)
+ funcs->glDisable(GL_DEPTH_TEST);
+
+ if (maskOfStatesToReset & DepthWriteStateMask)
+ funcs->glDepthMask(GL_TRUE); // reset to default
+
+ if (maskOfStatesToReset & FrontFaceStateMask)
+ funcs->glFrontFace(GL_CCW); // reset to default
+
+ if (maskOfStatesToReset & CullFaceStateMask)
+ funcs->glDisable(GL_CULL_FACE);
+
+ if (maskOfStatesToReset & DitheringStateMask)
+ funcs->glDisable(GL_DITHER);
+
+ if (maskOfStatesToReset & AlphaCoverageStateMask)
+ setAlphaCoverageEnabled(false);
+
+ if (maskOfStatesToReset & PointSizeMask)
+ pointSize(false, 1.0f); // reset to default
+
+ if (maskOfStatesToReset & PolygonOffsetStateMask)
+ funcs->glDisable(GL_POLYGON_OFFSET_FILL);
+
+ if (maskOfStatesToReset & ColorStateMask)
+ funcs->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+ if (maskOfStatesToReset & ClipPlaneMask) {
+ GLint max = maxClipPlaneCount();
+ for (GLint i = 0; i < max; ++i)
+ disableClipPlane(i);
+ }
+
+ if (maskOfStatesToReset & SeamlessCubemapMask)
+ setSeamlessCubemap(false);
+
+ if (maskOfStatesToReset & StencilOpMask)
+ funcs->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ if (maskOfStatesToReset & LineWidthMask)
+ funcs->glLineWidth(1.0f);
+
+#ifndef QT_OPENGL_ES_2
+ if (maskOfStatesToReset & RasterModeMask)
+ m_glHelper->rasterMode(GL_FRONT_AND_BACK, GL_FILL);
+#endif
+}
+
+void SubmissionContext::applyStateSet(RenderStateSet *ss)
+{
+ RenderStateSet* previousStates = currentStateSet();
+
+ const StateMaskSet invOurState = ~ss->stateMask();
+ // generate a mask for each set bit in previous, where we do not have
+ // the corresponding bit set.
+
+ StateMaskSet stateToReset = 0;
+ if (previousStates) {
+ stateToReset = previousStates->stateMask() & invOurState;
+ qCDebug(RenderStates) << "previous states " << QString::number(previousStates->stateMask(), 2);
+ }
+ qCDebug(RenderStates) << " current states " << QString::number(ss->stateMask(), 2) << "inverse " << QString::number(invOurState, 2) << " -> states to change: " << QString::number(stateToReset, 2);
+
+ // Reset states that aren't active in the current state set
+ resetMasked(stateToReset);
+
+ // Apply states that weren't in the previous state or that have
+ // different values
+ const QVector<StateVariant> statesToSet = ss->states();
+ for (const StateVariant &ds : statesToSet) {
+ if (previousStates && previousStates->contains(ds))
+ continue;
+ applyState(ds);
+ }
+}
+
+void SubmissionContext::clearColor(const QColor &color)
+{
+ if (m_currClearColorValue != color) {
+ m_currClearColorValue = color;
+ m_gl->functions()->glClearColor(color.redF(), color.greenF(), color.blueF(), color.alphaF());
+ }
+}
+
+void SubmissionContext::clearDepthValue(float depth)
+{
+ if (m_currClearDepthValue != depth) {
+ m_currClearDepthValue = depth;
+ m_gl->functions()->glClearDepthf(depth);
+ }
+}
+
+void SubmissionContext::clearStencilValue(int stencil)
+{
+ if (m_currClearStencilValue != stencil) {
+ m_currClearStencilValue = stencil;
+ m_gl->functions()->glClearStencil(stencil);
+ }
+}
+
+GLFence SubmissionContext::fenceSync()
+{
+ return m_glHelper->fenceSync();
+}
+
+void SubmissionContext::clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout)
+{
+ qDebug() << Q_FUNC_INFO << sync;
+ m_glHelper->clientWaitSync(sync, nanoSecTimeout);
+}
+
+void SubmissionContext::waitSync(GLFence sync)
+{
+ qDebug() << Q_FUNC_INFO << sync;
+ m_glHelper->waitSync(sync);
+}
+
+bool SubmissionContext::wasSyncSignaled(GLFence sync)
+{
+ return m_glHelper->wasSyncSignaled(sync);
+}
+
+void SubmissionContext::deleteSync(GLFence sync)
+{
+ m_glHelper->deleteSync(sync);
+}
+
+// It will be easier if the QGraphicContext applies the QUniformPack
+// than the other way around
+bool SubmissionContext::setParameters(ShaderParameterPack &parameterPack)
+{
+ static const int irradianceId = StringToInt::lookupId(QLatin1String("envLight.irradiance"));
+ static const int specularId = StringToInt::lookupId(QLatin1String("envLight.specular"));
+ // Activate textures and update TextureUniform in the pack
+ // with the correct textureUnit
+
+ // Set the pinned texture of the previous material texture
+ // to pinable so that we should easily find an available texture unit
+ m_textureContext.deactivateTexturesWithScope(TextureSubmissionContext::TextureScopeMaterial);
+ // Update the uniforms with the correct texture unit id's
+ PackUniformHash &uniformValues = parameterPack.uniforms();
+
+ // Fill Texture Uniform Value with proper texture units
+ // so that they can be applied as regular uniforms in a second step
+ for (int i = 0; i < parameterPack.textures().size(); ++i) {
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.textures().at(i);
+ // Given a Texture QNodeId, we retrieve the associated shared GLTexture
+ if (uniformValues.contains(namedTex.glslNameId)) {
+ GLTexture *t = m_renderer->glResourceManagers()->glTextureManager()->lookupResource(namedTex.nodeId);
+ if (t != nullptr) {
+ UniformValue &texUniform = uniformValues.value(namedTex.glslNameId);
+ if (texUniform.valueType() == UniformValue::TextureValue) {
+ const int texUnit = m_textureContext.activateTexture(TextureSubmissionContext::TextureScopeMaterial, m_gl, t);
+ texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit;
+ if (texUnit == -1) {
+ if (namedTex.glslNameId != irradianceId &&
+ namedTex.glslNameId != specularId) {
+ // Only return false if we are not dealing with env light textures
+ qCWarning(Backend) << "Unable to find suitable Texture Unit";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Fill Image Uniform Value with proper image units
+ // so that they can be applied as regular uniforms in a second step
+ for (int i = 0; i < parameterPack.images().size(); ++i) {
+ const ShaderParameterPack::NamedResource &namedTex = parameterPack.images().at(i);
+ // Given a Texture QNodeId, we retrieve the associated shared GLTexture
+ if (uniformValues.contains(namedTex.glslNameId)) {
+ ShaderImage *img = m_renderer->nodeManagers()->shaderImageManager()->lookupResource(namedTex.nodeId);
+ if (img != nullptr) {
+ GLTexture *t = m_renderer->glResourceManagers()->glTextureManager()->lookupResource(img->textureId());
+ if (t == nullptr) {
+ qCWarning(Backend) << "Shader Image referencing invalid texture";
+ continue;
+ } else {
+ UniformValue &imgUniform = uniformValues.value(namedTex.glslNameId);
+ if (imgUniform.valueType() == UniformValue::ShaderImageValue) {
+ const int imgUnit = m_imageContext.activateImage(img, t);
+ imgUniform.data<int>()[namedTex.uniformArrayIndex] = imgUnit;
+ if (imgUnit == -1) {
+ qCWarning(Backend) << "Unable to bind Image to Texture";
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ QOpenGLShaderProgram *shader = activeShader();
+
+ // TO DO: We could cache the binding points somehow and only do the binding when necessary
+ // for SSBO and UBO
+
+ // Bind Shader Storage block to SSBO and update SSBO
+ const QVector<BlockToSSBO> blockToSSBOs = parameterPack.shaderStorageBuffers();
+ for (const BlockToSSBO b : blockToSSBOs) {
+ Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID);
+ GLBuffer *ssbo = glBufferForRenderBuffer(cpuBuffer);
+ // bindShaderStorageBlock
+ // This is currently not required as we are introspecting the bindingIndex
+ // value from the shaders and not replacing them, making such a call useless
+ // bindShaderStorageBlock(shader->programId(), b.m_blockIndex, b.m_bindingIndex);
+ bindShaderStorageBlock(shader->programId(), b.m_blockIndex, b.m_bindingIndex);
+ // Needed to avoid conflict where the buffer would already
+ // be bound as a VertexArray
+ bindGLBuffer(ssbo, GLBuffer::ShaderStorageBuffer);
+ ssbo->bindBufferBase(this, b.m_bindingIndex, GLBuffer::ShaderStorageBuffer);
+ // TO DO: Make sure that there's enough binding points
+ }
+
+ // Bind UniformBlocks to UBO and update UBO from Buffer
+ // TO DO: Convert ShaderData to Buffer so that we can use that generic process
+ const QVector<BlockToUBO> blockToUBOs = parameterPack.uniformBuffers();
+ int uboIndex = 0;
+ for (const BlockToUBO &b : blockToUBOs) {
+ Buffer *cpuBuffer = m_renderer->nodeManagers()->bufferManager()->lookupResource(b.m_bufferID);
+ GLBuffer *ubo = glBufferForRenderBuffer(cpuBuffer);
+ bindUniformBlock(shader->programId(), b.m_blockIndex, uboIndex);
+ // Needed to avoid conflict where the buffer would already
+ // be bound as a VertexArray
+ bindGLBuffer(ubo, GLBuffer::UniformBuffer);
+ ubo->bindBufferBase(this, uboIndex++, GLBuffer::UniformBuffer);
+ // TO DO: Make sure that there's enough binding points
+ }
+
+ // Update uniforms in the Default Uniform Block
+ const PackUniformHash values = parameterPack.uniforms();
+ const QVector<ShaderUniform> activeUniforms = parameterPack.submissionUniforms();
+
+ for (const ShaderUniform &uniform : activeUniforms) {
+ // We can use [] as we are sure the the uniform wouldn't
+ // be un activeUniforms if there wasn't a matching value
+ const UniformValue &v = values.value(uniform.m_nameId);
+
+ // skip invalid textures/images
+ if ((v.valueType() == UniformValue::TextureValue ||
+ v.valueType() == UniformValue::ShaderImageValue) &&
+ *v.constData<int>() == -1)
+ continue;
+
+ applyUniform(uniform, v);
+ }
+ // if not all data is valid, the next frame will be rendered immediately
+ return true;
+}
+
+void SubmissionContext::enableAttribute(const VAOVertexAttribute &attr)
+{
+ // Bind buffer within the current VAO
+ GLBuffer *buf = m_renderer->glResourceManagers()->glBufferManager()->data(attr.bufferHandle);
+ Q_ASSERT(buf);
+ bindGLBuffer(buf, attr.attributeType);
+
+ // Don't use QOpenGLShaderProgram::setAttributeBuffer() because of QTBUG-43199.
+ // Use the introspection data and set the attribute explicitly
+ m_glHelper->enableVertexAttributeArray(attr.location);
+ m_glHelper->vertexAttributePointer(attr.shaderDataType,
+ attr.location,
+ attr.vertexSize,
+ attr.dataType,
+ GL_TRUE, // TODO: Support normalization property on QAttribute
+ attr.byteStride,
+ reinterpret_cast<const void *>(qintptr(attr.byteOffset)));
+
+
+ // Done by the helper if it supports it
+ if (attr.divisor != 0)
+ m_glHelper->vertexAttribDivisor(attr.location, attr.divisor);
+}
+
+void SubmissionContext::disableAttribute(const SubmissionContext::VAOVertexAttribute &attr)
+{
+ QOpenGLShaderProgram *prog = activeShader();
+ prog->disableAttributeArray(attr.location);
+}
+
+// Note: needs to be called while VAO is bound
+void SubmissionContext::specifyAttribute(const Attribute *attribute,
+ Buffer *buffer,
+ const ShaderAttribute *attributeDescription)
+{
+ const int location = attributeDescription->m_location;
+ if (location < 0) {
+ qCWarning(Backend) << "failed to resolve location for attribute:" << attribute->name();
+ return;
+ }
+
+ const GLint attributeDataType = glDataTypeFromAttributeDataType(attribute->vertexBaseType());
+ const HGLBuffer glBufferHandle = m_renderer->glResourceManagers()->glBufferManager()->lookupHandle(buffer->peerId());
+ Q_ASSERT(!glBufferHandle.isNull());
+ const GLBuffer::Type attributeType = attributeTypeToGLBufferType(attribute->attributeType());
+
+ int typeSize = 0;
+ int attrCount = 0;
+
+ if (attribute->vertexSize() >= 1 && attribute->vertexSize() <= 4) {
+ attrCount = 1;
+ } else if (attribute->vertexSize() == 9) {
+ typeSize = byteSizeFromType(attributeDataType);
+ attrCount = 3;
+ } else if (attribute->vertexSize() == 16) {
+ typeSize = byteSizeFromType(attributeDataType);
+ attrCount = 4;
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ Q_ASSERT(!glBufferHandle.isNull());
+ VAOVertexAttribute attr;
+ attr.bufferHandle = glBufferHandle;
+ attr.attributeType = attributeType;
+ attr.dataType = attributeDataType;
+ attr.divisor = attribute->divisor();
+ attr.vertexSize = attribute->vertexSize() / attrCount;
+ attr.byteStride = (attribute->byteStride() != 0) ? attribute->byteStride() : (attrCount * attrCount * typeSize);
+ attr.shaderDataType = attributeDescription->m_type;
+
+ for (int i = 0; i < attrCount; i++) {
+ attr.location = location + i;
+ attr.byteOffset = attribute->byteOffset() + (i * attrCount * typeSize);
+
+ enableAttribute(attr);
+
+ // Save this in the current emulated VAO
+ if (m_currentVAO)
+ m_currentVAO->saveVertexAttribute(attr);
+ }
+}
+
+void SubmissionContext::specifyIndices(Buffer *buffer)
+{
+ GLBuffer *buf = glBufferForRenderBuffer(buffer);
+ if (!bindGLBuffer(buf, GLBuffer::IndexBuffer))
+ qCWarning(Backend) << Q_FUNC_INFO << "binding index buffer failed";
+
+ // bound within the current VAO
+ // Save this in the current emulated VAO
+ if (m_currentVAO)
+ m_currentVAO->saveIndexAttribute(m_renderer->glResourceManagers()->glBufferManager()->lookupHandle(buffer->peerId()));
+}
+
+void SubmissionContext::updateBuffer(Buffer *buffer)
+{
+ const QHash<Qt3DCore::QNodeId, HGLBuffer>::iterator it = m_renderBufferHash.find(buffer->peerId());
+ if (it != m_renderBufferHash.end())
+ uploadDataToGLBuffer(buffer, m_renderer->glResourceManagers()->glBufferManager()->data(it.value()));
+}
+
+QByteArray SubmissionContext::downloadBufferContent(Buffer *buffer)
+{
+ const QHash<Qt3DCore::QNodeId, HGLBuffer>::iterator it = m_renderBufferHash.find(buffer->peerId());
+ if (it != m_renderBufferHash.end())
+ return downloadDataFromGLBuffer(buffer, m_renderer->glResourceManagers()->glBufferManager()->data(it.value()));
+ return QByteArray();
+}
+
+void SubmissionContext::releaseBuffer(Qt3DCore::QNodeId bufferId)
+{
+ auto it = m_renderBufferHash.find(bufferId);
+ if (it != m_renderBufferHash.end()) {
+ HGLBuffer glBuffHandle = it.value();
+ GLBuffer *glBuff = m_renderer->glResourceManagers()->glBufferManager()->data(glBuffHandle);
+
+ Q_ASSERT(glBuff);
+ // Destroy the GPU resource
+ glBuff->destroy(this);
+ // Destroy the GLBuffer instance
+ m_renderer->glResourceManagers()->glBufferManager()->releaseResource(bufferId);
+ // Remove Id - HGLBuffer entry
+ m_renderBufferHash.erase(it);
+ }
+}
+
+bool SubmissionContext::hasGLBufferForBuffer(Buffer *buffer)
+{
+ const QHash<Qt3DCore::QNodeId, HGLBuffer>::iterator it = m_renderBufferHash.find(buffer->peerId());
+ return (it != m_renderBufferHash.end());
+}
+
+GLBuffer *SubmissionContext::glBufferForRenderBuffer(Buffer *buf)
+{
+ if (!m_renderBufferHash.contains(buf->peerId()))
+ m_renderBufferHash.insert(buf->peerId(), createGLBufferFor(buf));
+ return m_renderer->glResourceManagers()->glBufferManager()->data(m_renderBufferHash.value(buf->peerId()));
+}
+
+HGLBuffer SubmissionContext::createGLBufferFor(Buffer *buffer)
+{
+ GLBuffer *b = m_renderer->glResourceManagers()->glBufferManager()->getOrCreateResource(buffer->peerId());
+ // b.setUsagePattern(static_cast<QOpenGLBuffer::UsagePattern>(buffer->usage()));
+ Q_ASSERT(b);
+ if (!b->create(this))
+ qCWarning(Render::Io) << Q_FUNC_INFO << "buffer creation failed";
+
+ return m_renderer->glResourceManagers()->glBufferManager()->lookupHandle(buffer->peerId());
+}
+
+bool SubmissionContext::bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type)
+{
+ if (type == GLBuffer::ArrayBuffer && buffer == m_boundArrayBuffer)
+ return true;
+
+ if (buffer->bind(this, type)) {
+ if (type == GLBuffer::ArrayBuffer)
+ m_boundArrayBuffer = buffer;
+ return true;
+ }
+ return false;
+}
+
+void SubmissionContext::uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer)
+{
+ if (!bindGLBuffer(b, GLBuffer::ArrayBuffer)) // We're uploading, the type doesn't matter here
+ qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed";
+ // If the buffer is dirty (hence being called here)
+ // there are two possible cases
+ // * setData was called changing the whole data or functor (or the usage pattern)
+ // * partial buffer updates where received
+
+ // TO DO: Handle usage pattern
+ QVector<Qt3DRender::QBufferUpdate> updates = std::move(buffer->pendingBufferUpdates());
+ for (auto it = updates.begin(); it != updates.end(); ++it) {
+ auto update = it;
+ // We have a partial update
+ if (update->offset >= 0) {
+ //accumulate sequential updates as single one
+ int bufferSize = update->data.size();
+ auto it2 = it + 1;
+ while ((it2 != updates.end())
+ && (it2->offset - update->offset == bufferSize)) {
+ bufferSize += it2->data.size();
+ ++it2;
+ }
+ update->data.resize(bufferSize);
+ while (it + 1 != it2) {
+ ++it;
+ update->data.replace(it->offset - update->offset, it->data.size(), it->data);
+ it->data.clear();
+ }
+ // TO DO: based on the number of updates .., it might make sense to
+ // sometime use glMapBuffer rather than glBufferSubData
+ b->update(this, update->data.constData(), update->data.size(), update->offset);
+ } else {
+ // We have an update that was done by calling QBuffer::setData
+ // which is used to resize or entirely clear the buffer
+ // Note: we use the buffer data directly in that case
+ const int bufferSize = buffer->data().size();
+ b->allocate(this, bufferSize, false); // orphan the buffer
+ b->allocate(this, buffer->data().constData(), bufferSize, false);
+ }
+ }
+
+ if (releaseBuffer) {
+ b->release(this);
+ m_boundArrayBuffer = nullptr;
+ }
+ qCDebug(Render::Io) << "uploaded buffer size=" << buffer->data().size();
+}
+
+QByteArray SubmissionContext::downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b)
+{
+ if (!bindGLBuffer(b, GLBuffer::ArrayBuffer)) // We're downloading, the type doesn't matter here
+ qCWarning(Render::Io) << Q_FUNC_INFO << "buffer bind failed";
+
+ QByteArray data = b->download(this, buffer->data().size());
+ return data;
+}
+
+void SubmissionContext::blitFramebuffer(Qt3DCore::QNodeId inputRenderTargetId,
+ Qt3DCore::QNodeId outputRenderTargetId,
+ QRect inputRect, QRect outputRect,
+ uint defaultFboId,
+ QRenderTargetOutput::AttachmentPoint inputAttachmentPoint,
+ QRenderTargetOutput::AttachmentPoint outputAttachmentPoint,
+ QBlitFramebuffer::InterpolationMethod interpolationMethod)
+{
+ GLuint inputFboId = defaultFboId;
+ bool inputBufferIsDefault = true;
+ if (!inputRenderTargetId.isNull()) {
+ RenderTarget *renderTarget = m_renderer->nodeManagers()->renderTargetManager()->lookupResource(inputRenderTargetId);
+ if (renderTarget) {
+ AttachmentPack attachments(renderTarget, m_renderer->nodeManagers()->attachmentManager());
+ if (m_renderTargets.contains(inputRenderTargetId))
+ inputFboId = updateRenderTarget(inputRenderTargetId, attachments, false);
+ else
+ inputFboId = createRenderTarget(inputRenderTargetId, attachments);
+ }
+ inputBufferIsDefault = false;
+ }
+
+ GLuint outputFboId = defaultFboId;
+ bool outputBufferIsDefault = true;
+ if (!outputRenderTargetId.isNull()) {
+ RenderTarget *renderTarget = m_renderer->nodeManagers()->renderTargetManager()->lookupResource(outputRenderTargetId);
+ if (renderTarget) {
+ AttachmentPack attachments(renderTarget, m_renderer->nodeManagers()->attachmentManager());
+ if (m_renderTargets.contains(outputRenderTargetId))
+ outputFboId = updateRenderTarget(outputRenderTargetId, attachments, false);
+ else
+ outputFboId = createRenderTarget(outputRenderTargetId, attachments);
+ }
+ outputBufferIsDefault = false;
+ }
+
+ // Up until this point the input and output rects are normal Qt rectangles.
+ // Convert them to GL rectangles (Y at bottom).
+ const int inputFboHeight = inputFboId == defaultFboId ? m_surfaceSize.height() : m_renderTargetsSize[inputFboId].height();
+ const GLint srcX0 = inputRect.left();
+ const GLint srcY0 = inputFboHeight - (inputRect.top() + inputRect.height());
+ const GLint srcX1 = srcX0 + inputRect.width();
+ const GLint srcY1 = srcY0 + inputRect.height();
+
+ const int outputFboHeight = outputFboId == defaultFboId ? m_surfaceSize.height() : m_renderTargetsSize[outputFboId].height();
+ const GLint dstX0 = outputRect.left();
+ const GLint dstY0 = outputFboHeight - (outputRect.top() + outputRect.height());
+ const GLint dstX1 = dstX0 + outputRect.width();
+ const GLint dstY1 = dstY0 + outputRect.height();
+
+ //Get the last bounded framebuffers
+ const GLuint lastDrawFboId = boundFrameBufferObject();
+
+ // Activate input framebuffer for reading
+ bindFramebuffer(inputFboId, GraphicsHelperInterface::FBORead);
+
+ // Activate output framebuffer for writing
+ bindFramebuffer(outputFboId, GraphicsHelperInterface::FBODraw);
+
+ //Bind texture
+ if (!inputBufferIsDefault)
+ readBuffer(GL_COLOR_ATTACHMENT0 + inputAttachmentPoint);
+
+ if (!outputBufferIsDefault) {
+ // Note that we use glDrawBuffers, not glDrawBuffer. The
+ // latter is not available with GLES.
+ const int buf = outputAttachmentPoint;
+ drawBuffers(1, &buf);
+ }
+
+ // Blit framebuffer
+ const GLenum mode = interpolationMethod ? GL_NEAREST : GL_LINEAR;
+ m_glHelper->blitFramebuffer(srcX0, srcY0, srcX1, srcY1,
+ dstX0, dstY0, dstX1, dstY1,
+ GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT,
+ mode);
+
+ // Reset draw buffer
+ bindFramebuffer(lastDrawFboId, GraphicsHelperInterface::FBOReadAndDraw);
+ if (outputAttachmentPoint != QRenderTargetOutput::Color0) {
+ const int buf = QRenderTargetOutput::Color0;
+ drawBuffers(1, &buf);
+ }
+}
+
+} // namespace Render
+} // namespace Qt3DRender of namespace
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h
new file mode 100644
index 000000000..16eca07ea
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/submissioncontext_p.h
@@ -0,0 +1,234 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_SUBMISSIONCONTEXT_H
+#define QT3DRENDER_RENDER_SUBMISSIONCONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <glbuffer_p.h>
+#include <glfence_p.h>
+#include <graphicscontext_p.h>
+#include <texturesubmissioncontext_p.h>
+#include <imagesubmissioncontext_p.h>
+#include <Qt3DRender/qclearbuffers.h>
+#include <Qt3DRender/qattribute.h>
+#include <Qt3DRender/private/handle_types_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAbstractOpenGLFunctions;
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class Renderer;
+class GraphicsHelperInterface;
+class RenderStateSet;
+class Material;
+class GLTexture;
+class RenderCommand;
+class RenderTarget;
+class AttachmentPack;
+class Attribute;
+class Buffer;
+class ShaderManager;
+struct StateVariant;
+
+typedef QPair<QString, int> NamedUniformLocation;
+
+class Q_AUTOTEST_EXPORT SubmissionContext : public GraphicsContext
+{
+public:
+ SubmissionContext();
+ ~SubmissionContext();
+
+ int id() const; // unique, small integer ID of this context
+ void setRenderer(Renderer *renderer) { m_renderer = renderer; }
+
+ bool beginDrawing(QSurface *surface);
+ void endDrawing(bool swapBuffers);
+ void releaseOpenGL();
+ void setOpenGLContext(QOpenGLContext* ctx);
+
+ // Viewport
+ void setViewport(const QRectF &viewport, const QSize &surfaceSize);
+ QRectF viewport() const { return m_viewport; }
+
+ // Shaders
+ bool activateShader(GLShader *shader);
+ QOpenGLShaderProgram *activeShader() const { return m_activeShader; }
+
+ // FBO
+ GLuint activeFBO() const { return m_activeFBO; }
+ void activateRenderTarget(const Qt3DCore::QNodeId id, const AttachmentPack &attachments, GLuint defaultFboId);
+ QSize renderTargetSize(const QSize &surfaceSize) const;
+ QImage readFramebuffer(const QRect &rect);
+ void blitFramebuffer(Qt3DCore::QNodeId outputRenderTargetId, Qt3DCore::QNodeId inputRenderTargetId,
+ QRect inputRect,
+ QRect outputRect, uint defaultFboId,
+ QRenderTargetOutput::AttachmentPoint inputAttachmentPoint,
+ QRenderTargetOutput::AttachmentPoint outputAttachmentPoint,
+ QBlitFramebuffer::InterpolationMethod interpolationMethod);
+
+ // Attributes
+ void specifyAttribute(const Attribute *attribute,
+ Buffer *buffer,
+ const ShaderAttribute *attributeDescription);
+ void specifyIndices(Buffer *buffer);
+
+ // Buffer
+ void updateBuffer(Buffer *buffer);
+ QByteArray downloadBufferContent(Buffer *buffer);
+ void releaseBuffer(Qt3DCore::QNodeId bufferId);
+ bool hasGLBufferForBuffer(Buffer *buffer);
+ GLBuffer *glBufferForRenderBuffer(Buffer *buf);
+
+ // Parameters
+ bool setParameters(ShaderParameterPack &parameterPack);
+
+ // RenderState
+ void setCurrentStateSet(RenderStateSet* ss);
+ RenderStateSet *currentStateSet() const;
+ void applyState(const StateVariant &state);
+
+ void resetMasked(qint64 maskOfStatesToReset);
+ void applyStateSet(RenderStateSet *ss);
+
+ // Wrappers
+ void clearColor(const QColor &color);
+ void clearDepthValue(float depth);
+ void clearStencilValue(int stencil);
+
+
+ // Fences
+ GLFence fenceSync();
+ void clientWaitSync(GLFence sync, GLuint64 nanoSecTimeout);
+ void waitSync(GLFence sync);
+ bool wasSyncSignaled(GLFence sync);
+ void deleteSync(GLFence sync);
+
+private:
+ void initialize();
+
+ // Material
+ Material* activeMaterial() const { return m_material; }
+ void setActiveMaterial(Material* rmat);
+
+ // FBO
+ void bindFrameBufferAttachmentHelper(GLuint fboId, const AttachmentPack &attachments);
+ void activateDrawBuffers(const AttachmentPack &attachments);
+ void resolveRenderTargetFormat();
+ GLuint createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments);
+ GLuint updateRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments, bool isActiveRenderTarget);
+
+ // Buffers
+ HGLBuffer createGLBufferFor(Buffer *buffer);
+ void uploadDataToGLBuffer(Buffer *buffer, GLBuffer *b, bool releaseBuffer = false);
+ QByteArray downloadDataFromGLBuffer(Buffer *buffer, GLBuffer *b);
+ bool bindGLBuffer(GLBuffer *buffer, GLBuffer::Type type);
+
+ bool m_ownCurrent;
+ const unsigned int m_id;
+ QSurface *m_surface;
+ QSize m_surfaceSize;
+
+ QOpenGLShaderProgram *m_activeShader;
+
+ QHash<Qt3DCore::QNodeId, HGLBuffer> m_renderBufferHash;
+ QHash<Qt3DCore::QNodeId, GLuint> m_renderTargets;
+ QHash<GLuint, QSize> m_renderTargetsSize;
+ QAbstractTexture::TextureFormat m_renderTargetFormat;
+
+ // cache some current state, to make sure we don't issue unnecessary GL calls
+ int m_currClearStencilValue;
+ float m_currClearDepthValue;
+ QColor m_currClearColorValue;
+
+ Material* m_material;
+ QRectF m_viewport;
+ GLuint m_activeFBO;
+
+ GLBuffer *m_boundArrayBuffer;
+ RenderStateSet* m_stateSet;
+ Renderer *m_renderer;
+ QByteArray m_uboTempArray;
+
+ TextureSubmissionContext m_textureContext;
+ ImageSubmissionContext m_imageContext;
+
+ // Attributes
+ friend class OpenGLVertexArrayObject;
+
+ struct VAOVertexAttribute
+ {
+ HGLBuffer bufferHandle;
+ GLBuffer::Type attributeType;
+ int location;
+ GLint dataType;
+ uint byteOffset;
+ uint vertexSize;
+ uint byteStride;
+ uint divisor;
+ GLenum shaderDataType;
+ };
+
+ using VAOIndexAttribute = HGLBuffer;
+ void enableAttribute(const VAOVertexAttribute &attr);
+ void disableAttribute(const VAOVertexAttribute &attr);
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_SUBMISSIONCONTEXT_H
diff --git a/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp b/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp
new file mode 100644
index 000000000..4f2ff80f5
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext.cpp
@@ -0,0 +1,225 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** 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 "texturesubmissioncontext_p.h"
+
+#include <graphicscontext_p.h>
+#include <gltexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+namespace Render {
+
+class TextureExtRendererLocker
+{
+public:
+ static void lock(GLTexture *tex)
+ {
+ if (!tex->isExternalRenderingEnabled())
+ return;
+ if (s_lockHash.keys().contains(tex)) {
+ ++s_lockHash[tex];
+ } else {
+ tex->externalRenderingLock()->lock();
+ s_lockHash[tex] = 1;
+ }
+ }
+ static void unlock(GLTexture *tex)
+ {
+ if (!tex->isExternalRenderingEnabled())
+ return;
+ if (!s_lockHash.keys().contains(tex))
+ return;
+
+ --s_lockHash[tex];
+ if (s_lockHash[tex] == 0) {
+ s_lockHash.remove(tex);
+ tex->externalRenderingLock()->unlock();
+ }
+ }
+private:
+ static QHash<GLTexture*, int> s_lockHash;
+};
+
+QHash<GLTexture*, int> TextureExtRendererLocker::s_lockHash = QHash<GLTexture*, int>();
+
+
+TextureSubmissionContext::TextureSubmissionContext()
+{
+
+}
+
+TextureSubmissionContext::~TextureSubmissionContext()
+{
+
+}
+
+void TextureSubmissionContext::initialize(GraphicsContext *context)
+{
+ m_activeTextures.resize(context->maxTextureUnitsCount());
+}
+
+void TextureSubmissionContext::endDrawing()
+{
+ decayTextureScores();
+ for (int i = 0; i < m_activeTextures.size(); ++i)
+ if (m_activeTextures[i].texture)
+ TextureExtRendererLocker::unlock(m_activeTextures[i].texture);
+}
+
+int TextureSubmissionContext::activateTexture(TextureSubmissionContext::TextureScope scope,
+ QOpenGLContext *m_gl,
+ GLTexture *tex)
+{
+ // Returns the texture unit to use for the texture
+ // This always return a valid unit, unless there are more textures than
+ // texture unit available for the current material
+ const int onUnit = assignUnitForTexture(tex);
+
+ // check we didn't overflow the available units
+ if (onUnit == -1)
+ return -1;
+
+ const int sharedTextureId = tex->sharedTextureId();
+ // We have a valid texture id provided by a shared context
+ if (sharedTextureId > 0) {
+ m_gl->functions()->glActiveTexture(GL_TEXTURE0 + onUnit);
+ const QAbstractTexture::Target target = tex->properties().target;
+ // For now we know that target values correspond to the GL values
+ m_gl->functions()->glBindTexture(target, tex->sharedTextureId());
+ } else {
+ // Texture must have been created and updated at this point
+ QOpenGLTexture *glTex = tex->getGLTexture();
+ if (glTex == nullptr)
+ return -1;
+ glTex->bind(uint(onUnit));
+ }
+ if (m_activeTextures[onUnit].texture != tex) {
+ if (m_activeTextures[onUnit].texture)
+ TextureExtRendererLocker::unlock(m_activeTextures[onUnit].texture);
+ m_activeTextures[onUnit].texture = tex;
+ TextureExtRendererLocker::lock(tex);
+ }
+
+#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
+ int err = m_gl->functions()->glGetError();
+ if (err)
+ qCWarning(Backend) << "GL error after activating texture" << QString::number(err, 16)
+ << tex->getGLTexture()->textureId() << "on unit" << onUnit;
+#endif
+
+ m_activeTextures[onUnit].score = 200;
+ m_activeTextures[onUnit].pinned = true;
+ m_activeTextures[onUnit].scope = scope;
+
+ return onUnit;
+}
+
+void TextureSubmissionContext::deactivateTexturesWithScope(TextureSubmissionContext::TextureScope ts)
+{
+ for (int u=0; u<m_activeTextures.size(); ++u) {
+ if (!m_activeTextures[u].pinned)
+ continue; // inactive, ignore
+
+ if (m_activeTextures[u].scope == ts) {
+ m_activeTextures[u].pinned = false;
+ m_activeTextures[u].score = qMax(m_activeTextures[u].score, 1) - 1;
+ }
+ } // of units iteration
+}
+
+void TextureSubmissionContext::deactivateTexture(GLTexture* tex)
+{
+ for (int u=0; u<m_activeTextures.size(); ++u) {
+ if (m_activeTextures[u].texture == tex) {
+ Q_ASSERT(m_activeTextures[u].pinned);
+ m_activeTextures[u].pinned = false;
+ return;
+ }
+ } // of units iteration
+
+ qCWarning(Backend) << Q_FUNC_INFO << "texture not active:" << tex;
+}
+
+/*!
+ \internal
+ Returns a texture unit for a texture, -1 if all texture units are assigned.
+ Tries to use the texture unit with the texture that hasn't been used for the longest time
+ if the texture happens not to be already pinned on a texture unit.
+ */
+int TextureSubmissionContext::assignUnitForTexture(GLTexture *tex)
+{
+ int lowestScoredUnit = -1;
+ int lowestScore = 0xfffffff;
+
+ for (int u=0; u<m_activeTextures.size(); ++u) {
+ if (m_activeTextures[u].texture == tex)
+ return u;
+ }
+
+ for (int u=0; u<m_activeTextures.size(); ++u) {
+ // No texture is currently active on the texture unit
+ // we save the texture unit with the texture that has been on there
+ // the longest time while not being used
+ if (!m_activeTextures[u].pinned) {
+ int score = m_activeTextures[u].score;
+ if (score < lowestScore) {
+ lowestScore = score;
+ lowestScoredUnit = u;
+ }
+ }
+ } // of units iteration
+
+ if (lowestScoredUnit == -1)
+ qCWarning(Backend) << Q_FUNC_INFO << "No free texture units!";
+
+ return lowestScoredUnit;
+}
+
+void TextureSubmissionContext::decayTextureScores()
+{
+ for (int u = 0; u < m_activeTextures.size(); u++)
+ m_activeTextures[u].score = qMax(m_activeTextures[u].score - 1, 0);
+}
+
+} // namespace Render
+} // namespace Qt3DRender of namespace
+
+QT_END_NAMESPACE
diff --git a/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h b/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h
new file mode 100644
index 000000000..3c84fe558
--- /dev/null
+++ b/src/plugins/renderers/opengl/graphicshelpers/texturesubmissioncontext_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Klaralvdalens Datakonsult AB (KDAB).
+** 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$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H
+#define QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <qglobal.h>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+
+namespace Qt3DRender {
+namespace Render {
+
+class GraphicsContext;
+class GLTexture;
+
+class Q_AUTOTEST_EXPORT TextureSubmissionContext
+{
+public:
+ enum TextureScope
+ {
+ TextureScopeMaterial = 0,
+ TextureScopeTechnique
+ // per-pass for deferred rendering?
+ };
+
+ TextureSubmissionContext();
+ ~TextureSubmissionContext();
+
+ void initialize(GraphicsContext *context);
+ void endDrawing();
+ int activateTexture(TextureScope scope, QOpenGLContext *gl, GLTexture* tex);
+ void deactivateTexture(GLTexture *tex);
+ void deactivateTexturesWithScope(TextureScope ts);
+
+private:
+ void decayTextureScores();
+ int assignUnitForTexture(GLTexture* tex);
+
+ // active textures, indexed by texture unit
+ struct ActiveTexture {
+ GLTexture *texture = nullptr;
+ int score = 0;
+ TextureScope scope = TextureScopeMaterial;
+ bool pinned = false;
+ };
+ QVector<ActiveTexture> m_activeTextures;
+};
+
+} // namespace Render
+} // namespace Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_TEXTURESUBMISSIONCONTEXT_H