diff --git a/examples/opengl/CMakeLists.txt b/examples/opengl/CMakeLists.txt index d2c7ece2fd..daecc37ffa 100644 --- a/examples/opengl/CMakeLists.txt +++ b/examples/opengl/CMakeLists.txt @@ -7,7 +7,6 @@ qt_internal_add_example(openglwindow) qt_internal_add_example(qopenglwindow) if(TARGET Qt6::Widgets) qt_internal_add_example(contextinfo) - qt_internal_add_example(threadedqopenglwidget) qt_internal_add_example(2dpainting) qt_internal_add_example(hellogl2) qt_internal_add_example(qopenglwidget) diff --git a/examples/opengl/opengl.pro b/examples/opengl/opengl.pro index 24cda20f63..4b0c760c4e 100644 --- a/examples/opengl/opengl.pro +++ b/examples/opengl/opengl.pro @@ -7,7 +7,6 @@ SUBDIRS = hellowindow \ qtHaveModule(widgets) { SUBDIRS += contextinfo \ - threadedqopenglwidget \ 2dpainting \ hellogl2 \ qopenglwidget \ diff --git a/examples/opengl/threadedqopenglwidget/CMakeLists.txt b/examples/opengl/threadedqopenglwidget/CMakeLists.txt deleted file mode 100644 index 6efecc4d07..0000000000 --- a/examples/opengl/threadedqopenglwidget/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -cmake_minimum_required(VERSION 3.16) -project(threadedqopenglwidget LANGUAGES CXX) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/opengl/threadedqopenglwidget") - -find_package(Qt6 REQUIRED COMPONENTS Core Gui OpenGL OpenGLWidgets Widgets) - -qt_standard_project_setup() - -qt_add_executable(threadedqopenglwidget - renderer.cpp renderer.h - glwidget.cpp glwidget.h - main.cpp - mainwindow.cpp mainwindow.h -) - -set_target_properties(threadedqopenglwidget PROPERTIES - WIN32_EXECUTABLE TRUE - MACOSX_BUNDLE TRUE -) - -target_link_libraries(threadedqopenglwidget PRIVATE - Qt6::Core - Qt6::Gui - Qt6::OpenGL - Qt6::OpenGLWidgets - Qt6::Widgets -) - -install(TARGETS threadedqopenglwidget - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/opengl/threadedqopenglwidget/glwidget.cpp b/examples/opengl/threadedqopenglwidget/glwidget.cpp deleted file mode 100644 index 6fbc61dd44..0000000000 --- a/examples/opengl/threadedqopenglwidget/glwidget.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "glwidget.h" -#include "renderer.h" - -#include -#include - -GLWidget::GLWidget(QWidget *parent) - : QOpenGLWidget(parent) -{ - setMinimumSize(300, 250); - - connect(this, &QOpenGLWidget::aboutToCompose, this, &GLWidget::onAboutToCompose); - connect(this, &QOpenGLWidget::frameSwapped, this, &GLWidget::onFrameSwapped); - connect(this, &QOpenGLWidget::aboutToResize, this, &GLWidget::onAboutToResize); - connect(this, &QOpenGLWidget::resized, this, &GLWidget::onResized); - - m_thread = new QThread; - m_renderer = new Renderer(this); - m_renderer->moveToThread(m_thread); - connect(m_thread, &QThread::finished, m_renderer, &QObject::deleteLater); - - connect(this, &GLWidget::renderRequested, m_renderer, &Renderer::render); - connect(m_renderer, &Renderer::contextWanted, this, &GLWidget::grabContext); - - m_thread->start(); -} - -GLWidget::~GLWidget() -{ - m_renderer->prepareExit(); - m_thread->quit(); - m_thread->wait(); - delete m_thread; -} - -void GLWidget::onAboutToCompose() -{ - // We are on the gui thread here. Composition is about to - // begin. Wait until the render thread finishes. - m_renderer->lockRenderer(); -} - -void GLWidget::onFrameSwapped() -{ - m_renderer->unlockRenderer(); - // Assuming a blocking swap, our animation is driven purely by the - // vsync in this example. - emit renderRequested(); -} - -void GLWidget::onAboutToResize() -{ - m_renderer->lockRenderer(); -} - -void GLWidget::onResized() -{ - m_renderer->unlockRenderer(); -} - -void GLWidget::grabContext() -{ - m_renderer->lockRenderer(); - QMutexLocker lock(m_renderer->grabMutex()); - context()->moveToThread(m_thread); - m_renderer->grabCond()->wakeAll(); - m_renderer->unlockRenderer(); -} diff --git a/examples/opengl/threadedqopenglwidget/glwidget.h b/examples/opengl/threadedqopenglwidget/glwidget.h deleted file mode 100644 index 12f234bc5c..0000000000 --- a/examples/opengl/threadedqopenglwidget/glwidget.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef GLWIDGET_H -#define GLWIDGET_H - -#include - -QT_FORWARD_DECLARE_CLASS(QThread) - -class Renderer; - -class GLWidget : public QOpenGLWidget -{ - Q_OBJECT -public: - explicit GLWidget(QWidget *parent = nullptr); - ~GLWidget(); - -protected: - void paintEvent(QPaintEvent *) override { } - -signals: - void renderRequested(); - -public slots: - void grabContext(); - -private slots: - void onAboutToCompose(); - void onFrameSwapped(); - void onAboutToResize(); - void onResized(); - -private: - QThread *m_thread; - Renderer *m_renderer; -}; - -#endif // GLWIDGET_H diff --git a/examples/opengl/threadedqopenglwidget/main.cpp b/examples/opengl/threadedqopenglwidget/main.cpp deleted file mode 100644 index efb84877f8..0000000000 --- a/examples/opengl/threadedqopenglwidget/main.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mainwindow.h" -#include "glwidget.h" - -#include - -static QString getGlString(QOpenGLFunctions *functions, GLenum name) -{ - if (const GLubyte *p = functions->glGetString(name)) - return QString::fromLatin1(reinterpret_cast(p)); - return QString(); -} - -int main( int argc, char ** argv ) -{ - QApplication a( argc, argv ); - - QCoreApplication::setApplicationName("Qt Threaded QOpenGLWidget Example"); - QCoreApplication::setOrganizationName("QtProject"); - QCoreApplication::setApplicationVersion(QT_VERSION_STR); - QCommandLineParser parser; - parser.setApplicationDescription(QCoreApplication::applicationName()); - parser.addHelpOption(); - parser.addVersionOption(); - QCommandLineOption singleOption("single", "Single thread"); - parser.addOption(singleOption); - parser.process(a); - - QSurfaceFormat format; - format.setDepthBufferSize(16); - QSurfaceFormat::setDefaultFormat(format); - - // Two top-level windows with two QOpenGLWidget children in each. - // The rendering for the four QOpenGLWidgets happens on four separate threads. - - GLWidget topLevelGlWidget; - QPoint pos = topLevelGlWidget.screen()->availableGeometry().topLeft() + QPoint(200, 200); - topLevelGlWidget.setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example top level")); - topLevelGlWidget.resize(200, 200); - topLevelGlWidget.move(pos); - topLevelGlWidget.show(); - auto *closeShortcut = new QShortcut(Qt::CTRL | Qt::Key_Q, &a, QApplication::closeAllWindows); - closeShortcut->setContext(Qt::ApplicationShortcut); - - const QString glInfo = getGlString(topLevelGlWidget.context()->functions(), GL_VENDOR) - + QLatin1Char('/') + getGlString(topLevelGlWidget.context()->functions(), GL_RENDERER); - - const bool supportsThreading = !glInfo.contains(QLatin1String("nouveau"), Qt::CaseInsensitive) - && !glInfo.contains(QLatin1String("ANGLE"), Qt::CaseInsensitive) - && !glInfo.contains(QLatin1String("llvmpipe"), Qt::CaseInsensitive); - - const QString toolTip = supportsThreading ? glInfo : glInfo + QStringLiteral("\ndoes not support threaded OpenGL."); - topLevelGlWidget.setToolTip(toolTip); - - std::unique_ptr mw1; - std::unique_ptr mw2; - if (!parser.isSet(singleOption)) { - if (supportsThreading) { - pos += QPoint(100, 100); - mw1.reset(new MainWindow); - mw1->setToolTip(toolTip); - mw1->move(pos); - mw1->setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example #1")); - mw1->show(); - pos += QPoint(100, 100); - mw2.reset(new MainWindow); - mw2->setToolTip(toolTip); - mw2->move(pos); - mw2->setWindowTitle(QStringLiteral("Threaded QOpenGLWidget example #2")); - mw2->show(); - } else { - qWarning() << toolTip; - } - } - - return a.exec(); -} diff --git a/examples/opengl/threadedqopenglwidget/mainwindow.cpp b/examples/opengl/threadedqopenglwidget/mainwindow.cpp deleted file mode 100644 index fd08c5713d..0000000000 --- a/examples/opengl/threadedqopenglwidget/mainwindow.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "mainwindow.h" -#include "glwidget.h" - -MainWindow::MainWindow() -{ - setMinimumSize(800, 400); - GLWidget *glwidget1 = new GLWidget(this); - glwidget1->resize(400, 400); - - GLWidget *glwidget2 = new GLWidget(this); - glwidget2->resize(400, 400); - glwidget2->move(400, 0); -} diff --git a/examples/opengl/threadedqopenglwidget/mainwindow.h b/examples/opengl/threadedqopenglwidget/mainwindow.h deleted file mode 100644 index 2dd8639a63..0000000000 --- a/examples/opengl/threadedqopenglwidget/mainwindow.h +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include - -class MainWindow : public QWidget -{ - Q_OBJECT - -public: - MainWindow(); -}; - -#endif diff --git a/examples/opengl/threadedqopenglwidget/renderer.cpp b/examples/opengl/threadedqopenglwidget/renderer.cpp deleted file mode 100644 index 2de19fb7a1..0000000000 --- a/examples/opengl/threadedqopenglwidget/renderer.cpp +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "renderer.h" -#include -#include -#include - -static const char VERTEX_SHADER[] = R"(attribute highp vec4 vertex; -attribute mediump vec3 normal; -uniform mediump mat4 matrix; -varying mediump vec4 color; -void main(void) -{ - vec3 toLight = normalize(vec3(0.0, 0.3, 1.0)); - float angle = max(dot(normal, toLight), 0.0); - vec3 col = vec3(0.40, 1.0, 0.0); - color = vec4(col * 0.2 + col * 0.8 * angle, 1.0); - color = clamp(color, 0.0, 1.0); - gl_Position = matrix * vertex; -} -)"; - -static const char FRAGMENT_SHADER[] = R"(varying mediump vec4 color; -void main(void) -{ - gl_FragColor = color; -} -)"; - -Renderer::Renderer(QOpenGLWidget *w) : - m_glwidget(w) -{ -} - -void Renderer::paintQtLogo() -{ - vbo.bind(); - program.setAttributeBuffer(vertexAttr, GL_FLOAT, 0, 3); - program.setAttributeBuffer(normalAttr, GL_FLOAT, vertices.count() * 3 * sizeof(GLfloat), 3); - vbo.release(); - - program.enableAttributeArray(vertexAttr); - program.enableAttributeArray(normalAttr); - - glDrawArrays(GL_TRIANGLES, 0, vertices.size()); - - program.disableAttributeArray(normalAttr); - program.disableAttributeArray(vertexAttr); -} - -// Some OpenGL implementations have serious issues with compiling and linking -// shaders on multiple threads concurrently. Avoid this. -Q_GLOBAL_STATIC(QMutex, initMutex) - -void Renderer::render() -{ - if (m_exiting) - return; - - QOpenGLContext *ctx = m_glwidget->context(); - if (!ctx) // QOpenGLWidget not yet initialized - return; - - // Grab the context. - m_grabMutex.lock(); - emit contextWanted(); - m_grabCond.wait(&m_grabMutex); - QMutexLocker lock(&m_renderMutex); - m_grabMutex.unlock(); - - if (m_exiting) - return; - - Q_ASSERT(ctx->thread() == QThread::currentThread()); - - // Make the context (and an offscreen surface) current for this thread. The - // QOpenGLWidget's fbo is bound in the context. - m_glwidget->makeCurrent(); - - if (!m_inited) { - m_inited = true; - initializeOpenGLFunctions(); - - QMutexLocker initLock(initMutex()); - QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this); - vshader->compileSourceCode(VERTEX_SHADER); - - QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this); - fshader->compileSourceCode(FRAGMENT_SHADER); - - program.addShader(vshader); - program.addShader(fshader); - program.link(); - - vertexAttr = program.attributeLocation("vertex"); - normalAttr = program.attributeLocation("normal"); - matrixUniform = program.uniformLocation("matrix"); - - m_fAngle = 0; - m_fScale = 1; - createGeometry(); - - vbo.create(); - vbo.bind(); - const int verticesSize = vertices.count() * 3 * sizeof(GLfloat); - vbo.allocate(verticesSize * 2); - vbo.write(0, vertices.constData(), verticesSize); - vbo.write(verticesSize, normals.constData(), verticesSize); - - m_elapsed.start(); - } - - //qDebug("%p elapsed %lld", QThread::currentThread(), m_elapsed.restart()); - - glClearColor(0.1f, 0.2f, 0.2f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glFrontFace(GL_CW); - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - - QMatrix4x4 modelview; - modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f); - modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f); - modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f); - modelview.scale(m_fScale); - modelview.translate(0.0f, -0.2f, 0.0f); - - program.bind(); - program.setUniformValue(matrixUniform, modelview); - paintQtLogo(); - program.release(); - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - m_fAngle += 1.0f; - - // Make no context current on this thread and move the QOpenGLWidget's - // context back to the gui thread. - m_glwidget->doneCurrent(); - ctx->moveToThread(qGuiApp->thread()); - - // Schedule composition. Note that this will use QueuedConnection, meaning - // that update() will be invoked on the gui thread. - QMetaObject::invokeMethod(m_glwidget, "update"); -} - -void Renderer::createGeometry() -{ - vertices.clear(); - normals.clear(); - - qreal x1 = +0.06f; - qreal y1 = -0.14f; - qreal x2 = +0.14f; - qreal y2 = -0.06f; - qreal x3 = +0.08f; - qreal y3 = +0.00f; - qreal x4 = +0.30f; - qreal y4 = +0.22f; - - quad(x1, y1, x2, y2, y2, x2, y1, x1); - quad(x3, y3, x4, y4, y4, x4, y3, x3); - - extrude(x1, y1, x2, y2); - extrude(x2, y2, y2, x2); - extrude(y2, x2, y1, x1); - extrude(y1, x1, x1, y1); - extrude(x3, y3, x4, y4); - extrude(x4, y4, y4, x4); - extrude(y4, x4, y3, x3); - - const int NumSectors = 100; - const qreal sectorAngle = 2 * qreal(M_PI) / NumSectors; - - for (int i = 0; i < NumSectors; ++i) { - qreal angle = i * sectorAngle; - qreal sinAngle = sin(angle); - qreal cosAngle = cos(angle); - qreal x5 = 0.30 * sinAngle; - qreal y5 = 0.30 * cosAngle; - qreal x6 = 0.20 * sinAngle; - qreal y6 = 0.20 * cosAngle; - - angle += sectorAngle; - sinAngle = sin(angle); - cosAngle = cos(angle); - qreal x7 = 0.20 * sinAngle; - qreal y7 = 0.20 * cosAngle; - qreal x8 = 0.30 * sinAngle; - qreal y8 = 0.30 * cosAngle; - - quad(x5, y5, x6, y6, x7, y7, x8, y8); - - extrude(x6, y6, x7, y7); - extrude(x8, y8, x5, y5); - } - - for (qsizetype i = 0; i < vertices.size(); ++i) - vertices[i] *= 2.0f; -} - -void Renderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4) -{ - vertices << QVector3D(x1, y1, -0.05f); - vertices << QVector3D(x2, y2, -0.05f); - vertices << QVector3D(x4, y4, -0.05f); - - vertices << QVector3D(x3, y3, -0.05f); - vertices << QVector3D(x4, y4, -0.05f); - vertices << QVector3D(x2, y2, -0.05f); - - QVector3D n = QVector3D::normal - (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; - - vertices << QVector3D(x4, y4, 0.05f); - vertices << QVector3D(x2, y2, 0.05f); - vertices << QVector3D(x1, y1, 0.05f); - - vertices << QVector3D(x2, y2, 0.05f); - vertices << QVector3D(x4, y4, 0.05f); - vertices << QVector3D(x3, y3, 0.05f); - - n = QVector3D::normal - (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; -} - -void Renderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2) -{ - vertices << QVector3D(x1, y1, +0.05f); - vertices << QVector3D(x2, y2, +0.05f); - vertices << QVector3D(x1, y1, -0.05f); - - vertices << QVector3D(x2, y2, -0.05f); - vertices << QVector3D(x1, y1, -0.05f); - vertices << QVector3D(x2, y2, +0.05f); - - QVector3D n = QVector3D::normal - (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; -} diff --git a/examples/opengl/threadedqopenglwidget/renderer.h b/examples/opengl/threadedqopenglwidget/renderer.h deleted file mode 100644 index e39f4810f8..0000000000 --- a/examples/opengl/threadedqopenglwidget/renderer.h +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2022 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef RENDERER_H -#define RENDERER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -QT_FORWARD_DECLARE_CLASS(QOpenGLWidget) - -class Renderer : public QObject, protected QOpenGLFunctions -{ - Q_OBJECT - -public: - explicit Renderer(QOpenGLWidget *w); - void lockRenderer() { m_renderMutex.lock(); } - void unlockRenderer() { m_renderMutex.unlock(); } - QMutex *grabMutex() { return &m_grabMutex; } - QWaitCondition *grabCond() { return &m_grabCond; } - void prepareExit() { m_exiting = true; m_grabCond.wakeAll(); } - -signals: - void contextWanted(); - -public slots: - void render(); - -private: - void paintQtLogo(); - void createGeometry(); - void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4); - void extrude(qreal x1, qreal y1, qreal x2, qreal y2); - - bool m_inited = false; - qreal m_fAngle = 0; - qreal m_fScale = 1; - QList vertices; - QList normals; - QOpenGLShaderProgram program; - QOpenGLBuffer vbo; - int vertexAttr = 0; - int normalAttr = 0; - int matrixUniform = 0; - QOpenGLWidget *m_glwidget = nullptr; - QMutex m_renderMutex; - QElapsedTimer m_elapsed; - QMutex m_grabMutex; - QWaitCondition m_grabCond; - bool m_exiting = false; -}; - -#endif // RENDERER_H diff --git a/examples/opengl/threadedqopenglwidget/threadedqopenglwidget.pro b/examples/opengl/threadedqopenglwidget/threadedqopenglwidget.pro deleted file mode 100644 index 46332ab7cb..0000000000 --- a/examples/opengl/threadedqopenglwidget/threadedqopenglwidget.pro +++ /dev/null @@ -1,13 +0,0 @@ -QT += widgets opengl openglwidgets - -SOURCES += main.cpp \ - glwidget.cpp \ - mainwindow.cpp \ - renderer.cpp - -HEADERS += glwidget.h \ - mainwindow.h \ - renderer.h - -target.path = $$[QT_INSTALL_EXAMPLES]/opengl/threadedqopenglwidget -INSTALLS += target