diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2018-03-12 08:32:35 +0100 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2020-02-05 11:33:49 +0100 |
commit | 0e115ff000fb294de8519bf5b39beee0d6bfa605 (patch) | |
tree | c66c1f19ad5e4b7fc4f3be7951fa74d1d4df64bb /src/plugins/renderers/opengl/graphicshelpers | |
parent | f1f387c22dac8748a7edb1f4aa1ea6dac7dfbdfd (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')
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 ¶meterPack) +{ + 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 ¶meterPack); + + // 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 |