From a6b8b03f864eac18c106d57e31a79b9078aa9625 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 11 Feb 2016 09:44:14 +0100 Subject: [PATCH] OpenGL: add support for compute shaders in GLES 3.1 OpenGL ES 3.1 introduces compute shaders. This patch enables them also in QOpenGLShader/QOpenGLShaderProgram. A GL/GLES example using QOpenGLShaderProgram for compute shaders is also included. Change-Id: I3951a302d7c2b096548f829b9b4578b5a525c453 Reviewed-by: Laszlo Agocs --- .../opengl/computegles31/Qt-logo-medium.png | Bin 0 -> 24817 bytes .../opengl/computegles31/computegles31.pro | 9 + .../opengl/computegles31/computegles31.qrc | 5 + examples/opengl/computegles31/glwindow.cpp | 423 ++++++++++++++++++ examples/opengl/computegles31/glwindow.h | 99 ++++ examples/opengl/computegles31/main.cpp | 118 +++++ examples/opengl/opengl.pro | 3 +- src/gui/opengl/qopenglshaderprogram.cpp | 221 +++++---- 8 files changed, 786 insertions(+), 92 deletions(-) create mode 100644 examples/opengl/computegles31/Qt-logo-medium.png create mode 100644 examples/opengl/computegles31/computegles31.pro create mode 100644 examples/opengl/computegles31/computegles31.qrc create mode 100644 examples/opengl/computegles31/glwindow.cpp create mode 100644 examples/opengl/computegles31/glwindow.h create mode 100644 examples/opengl/computegles31/main.cpp diff --git a/examples/opengl/computegles31/Qt-logo-medium.png b/examples/opengl/computegles31/Qt-logo-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ca1f18305761c1b0970fb40d50d3865f246c26 GIT binary patch literal 24817 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 ZYi%IxYE1Safexx + + Qt-logo-medium.png + + diff --git a/examples/opengl/computegles31/glwindow.cpp b/examples/opengl/computegles31/glwindow.cpp new file mode 100644 index 00000000000..d2cea169a13 --- /dev/null +++ b/examples/opengl/computegles31/glwindow.cpp @@ -0,0 +1,423 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "glwindow.h" +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include + +#ifndef GL_READ_WRITE +#define GL_READ_WRITE 0x88BA +#endif + +#ifndef GL_RGBA8 +#define GL_RGBA8 0x8058 +#endif + +#ifndef GL_SHADER_IMAGE_ACCESS_BARRIER_BIT +#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020 +#endif + +GLWindow::GLWindow() + : m_texImageInput(0), + m_texImageTmp(0), + m_texImageProcessed(0), + m_shaderDisplay(0), + m_shaderComputeV(0), + m_shaderComputeH(0), + m_blurRadius(0.0f), + m_animate(true) +{ + const float animationStart = 0.0; + const float animationEnd = 10.0; + const float animationLength = 1000; + + m_animationGroup = new QSequentialAnimationGroup(this); + m_animationGroup->setLoopCount(-1); + + m_animationForward = new QPropertyAnimation(this, QByteArrayLiteral("blurRadius")); + m_animationForward->setStartValue(animationStart); + m_animationForward->setEndValue(animationEnd); + m_animationForward->setDuration(animationLength); + m_animationGroup->addAnimation(m_animationForward); + + m_animationBackward = new QPropertyAnimation(this, QByteArrayLiteral("blurRadius")); + m_animationBackward->setStartValue(animationEnd); + m_animationBackward->setEndValue(animationStart); + m_animationBackward->setDuration(animationLength); + m_animationGroup->addAnimation(m_animationBackward); + + m_animationGroup->start(); +} + +GLWindow::~GLWindow() +{ + makeCurrent(); + delete m_texImageInput; + delete m_texImageProcessed; + delete m_texImageTmp; + delete m_shaderDisplay; + delete m_shaderComputeH; + delete m_shaderComputeV; + delete m_animationGroup; + delete m_animationForward; + delete m_animationBackward; +} + +void GLWindow::setBlurRadius(float blurRadius) +{ + int radius = int(blurRadius); + if (radius != m_blurRadius) { + m_blurRadius = radius; + update(); + } +} + +void GLWindow::setAnimating(bool animate) +{ + m_animate = animate; + if (animate) + m_animationGroup->start(); + else + m_animationGroup->stop(); +} + +void GLWindow::keyPressEvent(QKeyEvent *e) +{ + if (e->key() == Qt::Key_Space) { // pause + setAnimating(!m_animate); + } + update(); +} + + + + +static const char *vsDisplaySource = + "const vec4 vertices[4] = vec4[4] (\n" + " vec4( -1.0, 1.0, 0.0, 1.0),\n" + " vec4( -1.0, -1.0, 0.0, 1.0),\n" + " vec4( 1.0, 1.0, 0.0, 1.0),\n" + " vec4( 1.0, -1.0, 0.0, 1.0)\n" + ");\n" + "const vec2 texCoords[4] = vec2[4] (\n" + " vec2( 0.0, 1.0),\n" + " vec2( 0.0, 0.0),\n" + " vec2( 1.0, 1.0),\n" + " vec2( 1.0, 0.0)\n" + ");\n" + "out vec2 texCoord;\n" + "uniform mat4 matProjection;\n" + "uniform vec2 imageRatio;\n" + "void main() {\n" + " gl_Position = matProjection * ( vertices[gl_VertexID] * vec4(imageRatio,0,1) );\n" + " texCoord = texCoords[gl_VertexID];\n" + "}\n"; + +static const char *fsDisplaySource = + "in lowp vec2 texCoord; \n" + "uniform sampler2D samImage; \n" + "layout(location = 0) out lowp vec4 color;\n" + "void main() {\n" + " lowp vec4 texColor = texture(samImage,texCoord);\n" + " color = vec4(texColor.rgb, 1.0);\n" + "}\n"; + +static const char *csComputeSourceV = + //"#extension GL_EXT_gpu_shader5 : require \n" + "#define COMPUTEPATCHSIZE 32 \n" + "#define IMGFMT rgba8 \n" + "layout (local_size_x = COMPUTEPATCHSIZE, local_size_y = COMPUTEPATCHSIZE) in;\n" + "layout(binding=0, IMGFMT) uniform highp image2D inputImage; // Use a sampler to improve performance \n" + "layout(binding=1, IMGFMT) uniform highp image2D resultImage;\n" + "uniform int radius;\n" + "const float cutoff = 2.2;\n" + "float sigma = clamp(float(radius) / cutoff,0.02,100.0);\n" // Const initialization with dynamically uniform expressions doesn't work in GLES + "float expFactor = 1.0 / (2.0 * sigma * sigma);\n" // Same here + + "float gaussian(float distance) {\n" + " return exp( -(distance * distance) * expFactor);\n" + "}\n" + + "void main() {\n" + " ivec2 imgSize = imageSize(resultImage);\n" + " int x = int(gl_GlobalInvocationID.x);\n" + " int y = int(gl_GlobalInvocationID.y);\n" + " if ( (x >= imgSize.x) || (y >= imgSize.y) ) return;\n" + " vec4 sumPixels = vec4(0.0);\n" + " float sumWeights = 0.0;\n" + " int left = clamp(x - radius, 0, imgSize.x - 1);\n" + " int right = clamp(x + radius, 0, imgSize.x - 1);\n" + " int top = clamp(y - radius, 0, imgSize.y - 1);\n" + " int bottom = clamp(y + radius, 0, imgSize.y - 1);\n" + " for (int iY = top; iY <= bottom; iY++) {\n" + " float dy = float(abs(iY - y));\n" + " vec4 imgValue = imageLoad(inputImage, ivec2(x,iY));\n" + " float weight = gaussian(dy);\n" + " sumWeights += weight;\n" + " sumPixels += (imgValue * weight);\n" + " }\n" + " sumPixels /= sumWeights;\n" + " imageStore(resultImage, ivec2(x,y), sumPixels);" + "}\n"; + +static const char *csComputeSourceH = + //"#extension GL_EXT_gpu_shader5 : require \n" + "#define COMPUTEPATCHSIZE 32 \n" + "#define IMGFMT rgba8 \n" + "layout (local_size_x = COMPUTEPATCHSIZE, local_size_y = COMPUTEPATCHSIZE) in;\n" + "layout(binding=0, IMGFMT) uniform highp image2D inputImage; // Use a sampler to improve performance \n" + "layout(binding=1, IMGFMT) uniform highp image2D resultImage;\n" + "uniform int radius;\n" + "const float cutoff = 2.2;\n" + "float sigma = clamp(float(radius) / cutoff,0.02,100.0);\n" + "float expFactor = 1.0 / (2.0 * sigma * sigma);\n" + + "float gaussian(float distance) {\n" + " return exp( -(distance * distance) * expFactor);\n" + "}\n" + + "void main() {\n" + " ivec2 imgSize = imageSize(resultImage);\n" + " int x = int(gl_GlobalInvocationID.x);\n" + " int y = int(gl_GlobalInvocationID.y);\n" + " if ( (x >= imgSize.x) || (y >= imgSize.y) ) return;\n" + " vec4 sumPixels = vec4(0.0);\n" + " float sumWeights = 0.0;\n" + " int left = clamp(x - radius, 0, imgSize.x - 1);\n" + " int right = clamp(x + radius, 0, imgSize.x - 1);\n" + " int top = clamp(y - radius, 0, imgSize.y - 1);\n" + " int bottom = clamp(y + radius, 0, imgSize.y - 1);\n" + " for (int iX = left; iX <= right; iX++) {\n" + " float dx = float(abs(iX - x));\n" + " vec4 imgValue = imageLoad(inputImage, ivec2(iX,y));\n" + " float weight = gaussian(dx);\n" + " sumWeights += weight;\n" + " sumPixels += (imgValue * weight);\n" + " }\n" + " sumPixels /= sumWeights;\n" + " imageStore(resultImage, ivec2(x,y), sumPixels);" + "}\n"; + + + +QByteArray versionedShaderCode(const char *src) +{ + QByteArray versionedSrc; + + if (QOpenGLContext::currentContext()->isOpenGLES()) + versionedSrc.append(QByteArrayLiteral("#version 310 es\n")); + else + versionedSrc.append(QByteArrayLiteral("#version 430\n")); + + versionedSrc.append(src); + return versionedSrc; +} + +void computeProjection(int winWidth, int winHeight, int imgWidth, int imgHeight, QMatrix4x4 &outProjection, QSizeF &outQuadSize) +{ + float ratioImg = float(imgWidth) / float(imgHeight); + float ratioCanvas = float(winWidth) / float(winHeight); + + float correction = ratioImg / ratioCanvas; + float rescaleFactor = 1.0f; + float quadWidth = 1.0f; + float quadHeight = 1.0f; + + if (correction < 1.0f) // canvas larger than image -- height = 1.0, vertical black bands + { + quadHeight = 1.0f; + quadWidth = 1.0f * ratioImg; + rescaleFactor = ratioCanvas; + correction = 1.0f / rescaleFactor; + } + else // image larger than canvas -- width = 1.0, horizontal black bands + { + quadWidth = 1.0f; + quadHeight = 1.0f / ratioImg; + correction = 1.0f / ratioCanvas; + } + + const float frustumWidth = 1.0f * rescaleFactor; + const float frustumHeight = 1.0f * rescaleFactor * correction; + + outProjection = QMatrix4x4(); + outProjection.ortho( + -frustumWidth, + frustumWidth, + -frustumHeight, + frustumHeight, + -1.0f, + 1.0f); + outQuadSize = QSizeF(quadWidth,quadHeight); +} + +void GLWindow::initializeGL() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + qDebug() << "Got a " + << ctx->format().majorVersion() + << "." + << ctx->format().minorVersion() + << ((ctx->format().renderableType() == QSurfaceFormat::OpenGLES) ? (" GLES") : (" GL")) + << " context"; + //QOpenGLFunctions *f = ctx->functions(); + + if (m_texImageInput) { + delete m_texImageInput; + m_texImageInput = 0; + } + QImage img(":/Qt-logo-medium.png"); + Q_ASSERT(!img.isNull()); + m_texImageInput = new QOpenGLTexture(img.convertToFormat(QImage::Format_RGBA8888).mirrored()); + + if (m_texImageTmp) { + delete m_texImageTmp; + m_texImageTmp = 0; + } + m_texImageTmp = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texImageTmp->setFormat(m_texImageInput->format()); + m_texImageTmp->setSize(m_texImageInput->width(),m_texImageInput->height()); + m_texImageTmp->allocateStorage(QOpenGLTexture::RGBA,QOpenGLTexture::UInt8); // WTF? + + if (m_texImageProcessed) { + delete m_texImageProcessed; + m_texImageProcessed = 0; + } + m_texImageProcessed = new QOpenGLTexture(QOpenGLTexture::Target2D); + m_texImageProcessed->setFormat(m_texImageInput->format()); + m_texImageProcessed->setSize(m_texImageInput->width(),m_texImageInput->height()); + m_texImageProcessed->allocateStorage(QOpenGLTexture::RGBA,QOpenGLTexture::UInt8); + + m_texImageProcessed->setMagnificationFilter(QOpenGLTexture::Linear); + m_texImageProcessed->setMinificationFilter(QOpenGLTexture::Linear); + m_texImageProcessed->setWrapMode(QOpenGLTexture::ClampToEdge); + + if (m_shaderDisplay) { + delete m_shaderDisplay; + m_shaderDisplay = 0; + } + m_shaderDisplay = new QOpenGLShaderProgram; + // Prepend the correct version directive to the sources. The rest is the + // same, thanks to the common GLSL syntax. + m_shaderDisplay->addShaderFromSourceCode(QOpenGLShader::Vertex, versionedShaderCode(vsDisplaySource)); + m_shaderDisplay->addShaderFromSourceCode(QOpenGLShader::Fragment, versionedShaderCode(fsDisplaySource)); + m_shaderDisplay->link(); + + if (m_shaderComputeV) { + delete m_shaderComputeV; + m_shaderComputeV = 0; + } + m_shaderComputeV = new QOpenGLShaderProgram; + m_shaderComputeV->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceV)); + m_shaderComputeV->link(); + + if (m_shaderComputeH) { + delete m_shaderComputeH; + m_shaderComputeH = 0; + } + m_shaderComputeH = new QOpenGLShaderProgram; + m_shaderComputeH->addShaderFromSourceCode(QOpenGLShader::Compute, versionedShaderCode(csComputeSourceH)); + m_shaderComputeH->link(); +} + +void GLWindow::resizeGL(int w, int h) +{ + computeProjection(w,h,m_texImageInput->width(),m_texImageInput->height(),m_proj,m_quadSize); +} + +QSize getWorkGroups(int workGroupSize, const QSize &imageSize) +{ + int x = imageSize.width(); + x = (x % workGroupSize) ? (x / workGroupSize) + 1 : (x / workGroupSize); + int y = imageSize.height(); + y = (y % workGroupSize) ? (y / workGroupSize) + 1 : (y / workGroupSize); + return QSize(x,y); +} + +void GLWindow::paintGL() +{ + // Now use QOpenGLExtraFunctions instead of QOpenGLFunctions as we want to + // do more than what GL(ES) 2.0 offers. + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + + + // Process input image + QSize workGroups = getWorkGroups( 32, QSize(m_texImageInput->width(), m_texImageInput->height())); + // Pass 1 + f->glBindImageTexture(0, m_texImageInput->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + f->glBindImageTexture(1, m_texImageTmp->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + m_shaderComputeV->bind(); + m_shaderComputeV->setUniformValue("radius",m_blurRadius); + f->glDispatchCompute(workGroups.width(),workGroups.height(),1); + f->glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + m_shaderComputeV->release(); + // Pass 2 + f->glBindImageTexture(0, m_texImageTmp->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + f->glBindImageTexture(1, m_texImageProcessed->textureId(), 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + m_shaderComputeH->bind(); + m_shaderComputeH->setUniformValue("radius",m_blurRadius); + f->glDispatchCompute(workGroups.width(),workGroups.height(),1); + f->glMemoryBarrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT); + m_shaderComputeH->release(); + // Compute cleanup + f->glBindImageTexture(0, 0, 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + f->glBindImageTexture(1, 0, 0, 0, 0, GL_READ_WRITE, GL_RGBA8); + + // Display processed image + f->glClearColor(0, 0, 0, 1); + f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + m_texImageProcessed->bind(GL_TEXTURE0); + m_shaderDisplay->bind(); + m_shaderDisplay->setUniformValue("matProjection",m_proj); + m_shaderDisplay->setUniformValue("imageRatio",m_quadSize); + m_shaderDisplay->setUniformValue("samImage",0); + f->glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + m_shaderDisplay->release(); + m_texImageProcessed->release(GL_TEXTURE0); +} + diff --git a/examples/opengl/computegles31/glwindow.h b/examples/opengl/computegles31/glwindow.h new file mode 100644 index 00000000000..a55c5491bee --- /dev/null +++ b/examples/opengl/computegles31/glwindow.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLWIDGET_H +#define GLWIDGET_H + +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QOpenGLTexture; +class QOpenGLShaderProgram; +class QOpenGLBuffer; +class QOpenGLVertexArrayObject; + +QT_END_NAMESPACE + +class GLWindow : public QOpenGLWindow +{ + Q_OBJECT + Q_PROPERTY(float blurRadius READ blurRadius WRITE setBlurRadius) + +public: + GLWindow(); + ~GLWindow(); + + void initializeGL(); + void resizeGL(int w, int h); + void paintGL(); + + float blurRadius() const { return m_blurRadius; } + void setBlurRadius(float blurRadius); + +protected: + void keyPressEvent(QKeyEvent *e) Q_DECL_OVERRIDE; + void setAnimating(bool animate); + +private: + QPropertyAnimation *m_animationForward; + QPropertyAnimation *m_animationBackward; + QSequentialAnimationGroup *m_animationGroup; + QOpenGLTexture *m_texImageInput; + QOpenGLTexture *m_texImageTmp; + QOpenGLTexture *m_texImageProcessed; + QOpenGLShaderProgram *m_shaderDisplay; + QOpenGLShaderProgram *m_shaderComputeV; + QOpenGLShaderProgram *m_shaderComputeH; + QMatrix4x4 m_proj; + QSizeF m_quadSize; + + int m_blurRadius; + bool m_animate; +}; + +#endif diff --git a/examples/opengl/computegles31/main.cpp b/examples/opengl/computegles31/main.cpp new file mode 100644 index 00000000000..ff2a1e622df --- /dev/null +++ b/examples/opengl/computegles31/main.cpp @@ -0,0 +1,118 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "glwindow.h" + +bool OGLSupports(int major, int minor, bool gles = false) +{ + QOpenGLContext ctx; + QSurfaceFormat fmt; + fmt.setVersion(major, minor); + if (gles) + fmt.setRenderableType(QSurfaceFormat::OpenGLES); + else + fmt.setRenderableType(QSurfaceFormat::OpenGL); + + ctx.setFormat(fmt); + ctx.create(); + if (!ctx.isValid()) + return false; + int ctxMajor = ctx.format().majorVersion(); + int ctxMinor = ctx.format().minorVersion(); + bool isGles = (ctx.format().renderableType() == QSurfaceFormat::OpenGLES); + + if (isGles != gles) return false; + if (ctxMajor < major) return false; + if (ctxMajor == major && ctxMinor < minor) + return false; + return true; +} + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + qDebug() << "Support for GL 2.0 "<<( OGLSupports(2,0) ? "yes" : "no"); + qDebug() << "Support for GL 2.1 "<<( OGLSupports(2,1) ? "yes" : "no"); + qDebug() << "Support for GL 3.0 "<<( OGLSupports(3,0) ? "yes" : "no"); + qDebug() << "Support for GL 3.1 "<<( OGLSupports(3,1) ? "yes" : "no"); + qDebug() << "Support for GL 3.2 "<<( OGLSupports(3,2) ? "yes" : "no"); + qDebug() << "Support for GL 3.3 "<<( OGLSupports(3,3) ? "yes" : "no"); + qDebug() << "Support for GL 4.0 "<<( OGLSupports(4,0) ? "yes" : "no"); + qDebug() << "Support for GL 4.1 "<<( OGLSupports(4,1) ? "yes" : "no"); + qDebug() << "Support for GL 4.2 "<<( OGLSupports(4,2) ? "yes" : "no"); + qDebug() << "Support for GL 4.3 "<<( OGLSupports(4,3) ? "yes" : "no"); + qDebug() << "Support for GL 4.4 "<<( OGLSupports(4,4) ? "yes" : "no"); + qDebug() << "Support for GL 4.5 "<<( OGLSupports(4,5) ? "yes" : "no"); + qDebug() << "Support for GLES 2.0 "<<( OGLSupports(2,0,true) ? "yes" : "no"); + qDebug() << "Support for GLES 3.0 "<<( OGLSupports(3,0,true) ? "yes" : "no"); + qDebug() << "Support for GLES 3.1 "<<( OGLSupports(3,1,true) ? "yes" : "no"); + qDebug() << "Support for GLES 3.2 "<<( OGLSupports(3,2,true) ? "yes" : "no"); + + QSurfaceFormat fmt; + fmt.setDepthBufferSize(24); + + // Request OpenGL 4.3 compatibility or OpenGL ES 3.1. + if (OGLSupports(4,3)) { + qDebug("Requesting 4.3 compatibility context"); + fmt.setVersion(4, 3); + fmt.setRenderableType(QSurfaceFormat::OpenGL); + fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + } else if (OGLSupports(3,1,true)) { + qDebug("Requesting 3.1 GLES context"); + fmt.setVersion(3, 1); + fmt.setRenderableType(QSurfaceFormat::OpenGLES); + } else { + qWarning("Error: This system does not support OpenGL Compute Shaders! Exiting."); + return -1; + } + QSurfaceFormat::setDefaultFormat(fmt); + + GLWindow glWindow; + glWindow.showMaximized(); + + return app.exec(); +} diff --git a/examples/opengl/opengl.pro b/examples/opengl/opengl.pro index a102e087334..ef44201494b 100644 --- a/examples/opengl/opengl.pro +++ b/examples/opengl/opengl.pro @@ -14,7 +14,8 @@ qtHaveModule(widgets) { qopenglwidget \ cube \ textures \ - hellogles3 + hellogles3 \ + computegles31 } EXAMPLE_FILES += \ diff --git a/src/gui/opengl/qopenglshaderprogram.cpp b/src/gui/opengl/qopenglshaderprogram.cpp index f076e10e207..c0c0bb0a032 100644 --- a/src/gui/opengl/qopenglshaderprogram.cpp +++ b/src/gui/opengl/qopenglshaderprogram.cpp @@ -162,6 +162,79 @@ QT_BEGIN_NAMESPACE based on the core feature (requires OpenGL >= 4.3). */ + +// For GLES 3.1/3.2 +#ifndef GL_GEOMETRY_SHADER +#define GL_GEOMETRY_SHADER 0x8DD9 +#endif +#ifndef GL_TESS_CONTROL_SHADER +#define GL_TESS_CONTROL_SHADER 0x8E88 +#endif +#ifndef GL_TESS_EVALUATION_SHADER +#define GL_TESS_EVALUATION_SHADER 0x8E87 +#endif +#ifndef GL_COMPUTE_SHADER +#define GL_COMPUTE_SHADER 0x91B9 +#endif +#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES +#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 +#endif +#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS +#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 +#endif +#ifndef GL_PATCH_VERTICES +#define GL_PATCH_VERTICES 0x8E72 +#endif +#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL +#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 +#endif +#ifndef GL_PATCH_DEFAULT_INNER_LEVEL +#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 +#endif + +static inline bool isFormatGLES(const QSurfaceFormat &f) +{ + return (f.renderableType() == QSurfaceFormat::OpenGLES); +} + +static inline bool supportsGeometry(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair(3, 2)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + +static inline bool supportsCompute(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair(4, 3)); + else + return (f.version() >= qMakePair(3, 1)); +#else + return (f.version() >= qMakePair(3, 1)); +#endif +} + +static inline bool supportsTessellation(const QSurfaceFormat &f) +{ +#ifndef QT_OPENGL_ES_2 + if (!isFormatGLES(f)) + return (f.version() >= qMakePair(4, 0)); + else + return false; +#else + Q_UNUSED(f); + return false; +#endif +} + class QOpenGLShaderPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QOpenGLShader) @@ -171,22 +244,16 @@ public: , shaderType(type) , compiled(false) , glfuncs(new QOpenGLFunctions(ctx)) -#ifndef QT_OPENGL_ES_2 , supportsGeometryShaders(false) , supportsTessellationShaders(false) -#endif + , supportsComputeShaders(false) { -#ifndef QT_OPENGL_ES_2 - if (!ctx->isOpenGLES()) { - QSurfaceFormat f = ctx->format(); - - // Geometry shaders require OpenGL >= 3.2 - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = (f.version() >= qMakePair(3, 2)); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = (f.version() >= qMakePair(4, 0)); - } -#endif + if (shaderType & QOpenGLShader::Geometry) + supportsGeometryShaders = supportsGeometry(ctx->format()); + else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + supportsTessellationShaders = supportsTessellation(ctx->format()); + else if (shaderType & QOpenGLShader::Compute) + supportsComputeShaders = supportsCompute(ctx->format()); } ~QOpenGLShaderPrivate(); @@ -197,13 +264,13 @@ public: QOpenGLFunctions *glfuncs; -#ifndef QT_OPENGL_ES_2 // Support for geometry shaders bool supportsGeometryShaders; - // Support for tessellation shaders bool supportsTessellationShaders; -#endif + // Support for compute shaders + bool supportsComputeShaders; + bool create(); bool compile(QOpenGLShader *q); @@ -232,21 +299,15 @@ bool QOpenGLShaderPrivate::create() GLuint shader; if (shaderType == QOpenGLShader::Vertex) { shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); -#if defined(QT_OPENGL_3_2) } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); -#endif -#if defined(QT_OPENGL_4) } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); -#endif -#if defined(QT_OPENGL_4_3) - } else if (shaderType == QOpenGLShader::Compute) { + } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); -#endif - } else { + } else if (shaderType == QOpenGLShader::Fragment) { shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); } if (!shader) { @@ -3209,10 +3270,8 @@ void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4 int QOpenGLShaderProgram::maxGeometryOutputVertices() const { GLint n = 0; -#if defined(QT_OPENGL_3_2) Q_D(const QOpenGLShaderProgram); d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); -#endif return n; } @@ -3236,7 +3295,7 @@ int QOpenGLShaderProgram::maxGeometryOutputVertices() const */ void QOpenGLShaderProgram::setPatchVertexCount(int count) { -#if defined(QT_OPENGL_4) +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glPatchParameteri(GL_PATCH_VERTICES, count); @@ -3255,13 +3314,15 @@ void QOpenGLShaderProgram::setPatchVertexCount(int count) */ int QOpenGLShaderProgram::patchVertexCount() const { +#ifndef QT_OPENGL_ES_2 int patchVertices = 0; -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices); -#endif return patchVertices; +#else + return 0; +#endif } /*! @@ -3283,21 +3344,21 @@ int QOpenGLShaderProgram::patchVertexCount() const */ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector &levels) { -#if defined(QT_OPENGL_4) - QVector tessLevels = levels; - - // Ensure we have the required 4 outer tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 4; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector tessLevels = levels; + + // Ensure we have the required 4 outer tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 4; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3320,13 +3381,15 @@ void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector QOpenGLShaderProgram::defaultOuterTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector tessLevels(4, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector(); +#endif } /*! @@ -3348,21 +3411,21 @@ QVector QOpenGLShaderProgram::defaultOuterTessellationLevels() const */ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector &levels) { -#if defined(QT_OPENGL_4) - QVector tessLevels = levels; - - // Ensure we have the required 2 inner tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 2; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - +#ifndef QT_OPENGL_ES_2 Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) + if (d->tessellationFuncs) { + QVector tessLevels = levels; + + // Ensure we have the required 2 inner tessellation levels + // Use default of 1 for missing entries (same as spec) + const int argCount = 2; + if (tessLevels.size() < argCount) { + tessLevels.reserve(argCount); + for (int i = tessLevels.size(); i < argCount; ++i) + tessLevels.append(1.0f); + } d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); + } #else Q_UNUSED(levels); #endif @@ -3385,13 +3448,15 @@ void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector QOpenGLShaderProgram::defaultInnerTessellationLevels() const { +#ifndef QT_OPENGL_ES_2 QVector tessLevels(2, 1.0f); -#if defined(QT_OPENGL_4) Q_D(const QOpenGLShaderProgram); if (d->tessellationFuncs) d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); -#endif return tessLevels; +#else + return QVector(); +#endif } @@ -3404,16 +3469,11 @@ QVector QOpenGLShaderProgram::defaultInnerTessellationLevels() const */ bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) { -#if !defined(QT_OPENGL_ES_2) if (!context) context = QOpenGLContext::currentContext(); if (!context) return false; return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); -#else - Q_UNUSED(context); - return true; -#endif } /*! @@ -3444,33 +3504,12 @@ bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0) return false; - QSurfaceFormat format = context->format(); - if (type == Geometry) { -#ifndef QT_OPENGL_ES_2 - // Geometry shaders require OpenGL 3.2 or newer - QSurfaceFormat format = context->format(); - return (!context->isOpenGLES()) - && (format.version() >= qMakePair(3, 2)); -#else - // No geometry shader support in OpenGL ES2 - return false; -#endif - } else if (type == TessellationControl || type == TessellationEvaluation) { -#if !defined(QT_OPENGL_ES_2) - return (!context->isOpenGLES()) - && (format.version() >= qMakePair(4, 0)); -#else - // No tessellation shader support in OpenGL ES2 - return false; -#endif - } else if (type == Compute) { -#if defined(QT_OPENGL_4_3) - return (format.version() >= qMakePair(4, 3)); -#else - // No compute shader support without OpenGL 4.3 or newer - return false; -#endif - } + if (type & QOpenGLShader::Geometry) + return supportsGeometry(context->format()); + else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) + return supportsTessellation(context->format()); + else if (type & QOpenGLShader::Compute) + return supportsCompute(context->format()); // Unconditional support of vertex and fragment shaders implicitly assumes // a minimum OpenGL version of 2.0