From a6b8b03f864eac18c106d57e31a79b9078aa9625 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Thu, 11 Feb 2016 09:44:14 +0100 Subject: 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 --- examples/opengl/computegles31/Qt-logo-medium.png | Bin 0 -> 24817 bytes examples/opengl/computegles31/computegles31.pro | 9 + examples/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 +- 7 files changed, 656 insertions(+), 1 deletion(-) 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 (limited to 'examples') diff --git a/examples/opengl/computegles31/Qt-logo-medium.png b/examples/opengl/computegles31/Qt-logo-medium.png new file mode 100644 index 0000000000..a1ca1f1830 Binary files /dev/null and b/examples/opengl/computegles31/Qt-logo-medium.png differ diff --git a/examples/opengl/computegles31/computegles31.pro b/examples/opengl/computegles31/computegles31.pro new file mode 100644 index 0000000000..5b9d7e4387 --- /dev/null +++ b/examples/opengl/computegles31/computegles31.pro @@ -0,0 +1,9 @@ +HEADERS = $$PWD/glwindow.h + +SOURCES = $$PWD/glwindow.cpp \ + $$PWD/main.cpp + +RESOURCES += computegles31.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/opengl/computegles31 +INSTALLS += target diff --git a/examples/opengl/computegles31/computegles31.qrc b/examples/opengl/computegles31/computegles31.qrc new file mode 100644 index 0000000000..b99eb0a82e --- /dev/null +++ b/examples/opengl/computegles31/computegles31.qrc @@ -0,0 +1,5 @@ + + + Qt-logo-medium.png + + diff --git a/examples/opengl/computegles31/glwindow.cpp b/examples/opengl/computegles31/glwindow.cpp new file mode 100644 index 0000000000..d2cea169a1 --- /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 0000000000..a55c5491be --- /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 0000000000..ff2a1e622d --- /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 a102e08733..ef44201494 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 += \ -- cgit v1.2.3