summaryrefslogtreecommitdiffstats
path: root/tests/auto/qglthreads/tst_qglthreads.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/qglthreads/tst_qglthreads.cpp')
-rw-r--r--tests/auto/qglthreads/tst_qglthreads.cpp757
1 files changed, 0 insertions, 757 deletions
diff --git a/tests/auto/qglthreads/tst_qglthreads.cpp b/tests/auto/qglthreads/tst_qglthreads.cpp
deleted file mode 100644
index 472379ab7a..0000000000
--- a/tests/auto/qglthreads/tst_qglthreads.cpp
+++ /dev/null
@@ -1,757 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtTest/QtTest>
-#include <QtCore/QtCore>
-#include <QtGui/QtGui>
-#include <QtOpenGL/QtOpenGL>
-#include "tst_qglthreads.h"
-
-#ifdef Q_OS_SYMBIAN
-#define RUNNING_TIME 2000 // save GPU mem by running shorter time.
-#else
-#define RUNNING_TIME 5000
-#endif
-
-
-
-
-tst_QGLThreads::tst_QGLThreads(QObject *parent)
- : QObject(parent)
-{
-}
-
-/*
-
- swapInThread
-
- The purpose of this testcase is to verify that it is possible to do rendering into
- a GL context from the GUI thread, then swap the contents in from a background thread.
-
- The usecase for this is to have the background thread do the waiting for vertical
- sync while the GUI thread is idle.
-
- Currently the locking is handled directly in the paintEvent(). For the actual usecase
- in Qt, the locking is done in the windowsurface before starting any drawing while
- unlocking is done after all drawing has been done.
- */
-
-
-class SwapThread : public QThread
-{
- Q_OBJECT
-public:
- SwapThread(QGLWidget *widget)
- : m_widget(widget)
- {
- moveToThread(this);
- }
-
- void run() {
- QTime time;
- time.start();
- while (time.elapsed() < RUNNING_TIME) {
- lock();
- wait();
-
- m_widget->makeCurrent();
- m_widget->swapBuffers();
- m_widget->doneCurrent();
- unlock();
- }
- }
-
- void lock() { m_mutex.lock(); }
- void unlock() { m_mutex.unlock(); }
-
- void wait() { m_wait_condition.wait(&m_mutex); }
- void notify() { m_wait_condition.wakeAll(); }
-
-private:
- QGLWidget *m_widget;
- QMutex m_mutex;
- QWaitCondition m_wait_condition;
-};
-
-class ForegroundWidget : public QGLWidget
-{
-public:
- ForegroundWidget(const QGLFormat &format)
- : QGLWidget(format), m_thread(0)
- {
- setAutoBufferSwap(false);
- }
-
- void paintEvent(QPaintEvent *)
- {
- m_thread->lock();
- makeCurrent();
- QPainter p(this);
- p.fillRect(rect(), QColor(rand() % 256, rand() % 256, rand() % 256));
- p.setPen(Qt::red);
- p.setFont(QFont("SansSerif", 24));
- p.drawText(rect(), Qt::AlignCenter, "This is an autotest");
- p.end();
- doneCurrent();
- m_thread->notify();
- m_thread->unlock();
-
- update();
- }
-
- void setThread(SwapThread *thread) {
- m_thread = thread;
- }
-
- SwapThread *m_thread;
-};
-
-void tst_QGLThreads::swapInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll);
-#endif
-
- QGLFormat format;
- format.setSwapInterval(1);
- ForegroundWidget widget(format);
- SwapThread thread(&widget);
- widget.setThread(&thread);
- widget.show();
-
- QTest::qWaitForWindowShown(&widget);
- thread.start();
-
- while (thread.isRunning()) {
- qApp->processEvents();
- }
-
- widget.hide();
-
- QVERIFY(true);
-}
-
-
-
-
-
-
-
-/*
- textureUploadInThread
-
- The purpose of this testcase is to verify that doing texture uploads in a background
- thread is possible and that it works.
- */
-
-class CreateAndUploadThread : public QThread
-{
- Q_OBJECT
-public:
- CreateAndUploadThread(QGLWidget *shareWidget)
- {
- m_gl = new QGLWidget(0, shareWidget);
- moveToThread(this);
- }
-
- ~CreateAndUploadThread()
- {
- delete m_gl;
- }
-
- void run() {
- m_gl->makeCurrent();
- QTime time;
- time.start();
- while (time.elapsed() < RUNNING_TIME) {
- int width = 400;
- int height = 300;
-#ifdef Q_OS_SYMBIAN
- // GPU mem is very scarce resource on Symbian currently.
- // That's why we create only small textures.
- width = 50;
- height = 20;
-#endif
- QImage image(width, height, QImage::Format_RGB32);
- QPainter p(&image);
- p.fillRect(image.rect(), QColor(rand() % 256, rand() % 256, rand() % 256));
- p.setPen(Qt::red);
- p.setFont(QFont("SansSerif", 24));
- p.drawText(image.rect(), Qt::AlignCenter, "This is an autotest");
- p.end();
- m_gl->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
-
- createdAndUploaded(image);
- }
- }
-
-signals:
- void createdAndUploaded(const QImage &image);
-
-private:
- QGLWidget *m_gl;
-};
-
-class TextureDisplay : public QGLWidget
-{
- Q_OBJECT
-public:
- void paintEvent(QPaintEvent *) {
- QPainter p(this);
- for (int i=0; i<m_images.size(); ++i) {
- p.drawImage(m_positions.at(i), m_images.at(i));
- m_positions[i] += QPoint(1, 1);
- }
- update();
- }
-
-public slots:
- void receiveImage(const QImage &image) {
- m_images << image;
- m_positions << QPoint(-rand() % width() / 2, -rand() % height() / 2);
-
- if (m_images.size() > 100) {
- m_images.takeFirst();
- m_positions.takeFirst();
- }
- }
-
-private:
- QList <QImage> m_images;
- QList <QPoint> m_positions;
-};
-
-void tst_QGLThreads::textureUploadInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on mac as they were causing reboots", SkipAll);
-#endif
-
- TextureDisplay display;
- CreateAndUploadThread thread(&display);
-
- connect(&thread, SIGNAL(createdAndUploaded(QImage)), &display, SLOT(receiveImage(QImage)));
-
- display.show();
- QTest::qWaitForWindowShown(&display);
-
- thread.start();
-
- while (thread.isRunning()) {
- qApp->processEvents();
- }
-
- QVERIFY(true);
-}
-
-
-
-
-
-
-/*
- renderInThread
-
- This test sets up a scene and renders it in a different thread.
- For simplicity, the scene is simply a bunch of rectangles, but
- if that works, we're in good shape..
- */
-
-static inline float qrandom() { return (rand() % 100) / 100.f; }
-
-void renderAScene(int w, int h)
-{
-#ifdef QT_OPENGL_ES_2
- QGLShaderProgram program;
- program.addShaderFromSourceCode(QGLShader::Vertex, "attribute highp vec2 pos; void main() { gl_Position = vec4(pos.xy, 1.0, 1.0); }");
- program.addShaderFromSourceCode(QGLShader::Fragment, "uniform lowp vec4 color; void main() { gl_FragColor = color; }");
- program.bindAttributeLocation("pos", 0);
- program.bind();
- int colorId = program.uniformLocation("color");
-
- glEnableVertexAttribArray(0);
-
- for (int i=0; i<1000; ++i) {
- GLfloat pos[] = {
- (rand() % 100) / 100.,
- (rand() % 100) / 100.,
- (rand() % 100) / 100.,
- (rand() % 100) / 100.,
- (rand() % 100) / 100.,
- (rand() % 100) / 100.
- };
-
- glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, pos);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- }
-#else
- glViewport(0, 0, w, h);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustum(0, w, h, 0, 1, 100);
- glTranslated(0, 0, -1);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- for (int i=0;i<1000; ++i) {
- glBegin(GL_TRIANGLES);
- glColor3f(qrandom(), qrandom(), qrandom());
- glVertex2f(qrandom() * w, qrandom() * h);
- glColor3f(qrandom(), qrandom(), qrandom());
- glVertex2f(qrandom() * w, qrandom() * h);
- glColor3f(qrandom(), qrandom(), qrandom());
- glVertex2f(qrandom() * w, qrandom() * h);
- glEnd();
- }
-#endif
-}
-
-class ThreadSafeGLWidget : public QGLWidget
-{
-public:
- ThreadSafeGLWidget(QWidget *parent = 0) : QGLWidget(parent) {}
- void paintEvent(QPaintEvent *)
- {
- // ignored as we're anyway swapping as fast as we can
- };
-
- void resizeEvent(QResizeEvent *e)
- {
- mutex.lock();
- newSize = e->size();
- mutex.unlock();
- };
-
- QMutex mutex;
- QSize newSize;
-};
-
-class SceneRenderingThread : public QThread
-{
- Q_OBJECT
-public:
- SceneRenderingThread(ThreadSafeGLWidget *widget)
- : m_widget(widget)
- {
- moveToThread(this);
- m_size = widget->size();
- }
-
- void run() {
- QTime time;
- time.start();
- failure = false;
-
- m_widget->makeCurrent();
-
- while (time.elapsed() < RUNNING_TIME && !failure) {
-
-
- m_widget->mutex.lock();
- QSize s = m_widget->newSize;
- m_widget->mutex.unlock();
-
- if (s != m_size) {
- glViewport(0, 0, s.width(), s.height());
- }
-
- if (QGLContext::currentContext() != m_widget->context()) {
- failure = true;
- break;
- }
-
- glClear(GL_COLOR_BUFFER_BIT);
-
- int w = m_widget->width();
- int h = m_widget->height();
-
- renderAScene(w, h);
-
- int color;
- glReadPixels(w / 2, h / 2, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &color);
-
- m_widget->swapBuffers();
- }
-
- m_widget->doneCurrent();
- }
-
- bool failure;
-
-private:
- ThreadSafeGLWidget *m_widget;
- QSize m_size;
-};
-
-void tst_QGLThreads::renderInThread_data()
-{
- QTest::addColumn<bool>("resize");
- QTest::addColumn<bool>("update");
-
- QTest::newRow("basic") << false << false;
- QTest::newRow("with-resize") << true << false;
- QTest::newRow("with-update") << false << true;
- QTest::newRow("with-resize-and-update") << true << true;
-}
-
-void tst_QGLThreads::renderInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll);
-#endif
-
-#ifdef Q_OS_SYMBIAN
- QSKIP("OpenGL threading tests are disabled on Symbian as accessing RWindow from a secondary thread is not supported", SkipAll);
-#endif
-
- QFETCH(bool, resize);
- QFETCH(bool, update);
-
- ThreadSafeGLWidget widget;
- widget.resize(200, 200);
- SceneRenderingThread thread(&widget);
-
- widget.show();
- QTest::qWaitForWindowShown(&widget);
- widget.doneCurrent();
-
- thread.start();
-
- int value = 10;
- while (thread.isRunning()) {
- if (resize)
- widget.resize(200 + value, 200 + value);
- if (update)
- widget.update(100 + value, 100 + value, 20, 20);
- qApp->processEvents();
- value = -value;
-
- QThread::msleep(100);
- }
-
- QVERIFY(!thread.failure);
-}
-
-class Device
-{
-public:
- virtual ~Device() {}
- virtual QPaintDevice *realPaintDevice() = 0;
- virtual void prepareDevice() {}
-};
-
-class GLWidgetWrapper : public Device
-{
-public:
- GLWidgetWrapper() {
- widget.resize(150, 150);
- widget.show();
- QTest::qWaitForWindowShown(&widget);
- widget.doneCurrent();
- }
- QPaintDevice *realPaintDevice() { return &widget; }
-
- ThreadSafeGLWidget widget;
-};
-
-class PixmapWrapper : public Device
-{
-public:
- PixmapWrapper() { pixmap = new QPixmap(512, 512); }
- ~PixmapWrapper() { delete pixmap; }
- QPaintDevice *realPaintDevice() { return pixmap; }
-
- QPixmap *pixmap;
-};
-
-class PixelBufferWrapper : public Device
-{
-public:
- PixelBufferWrapper() { pbuffer = new QGLPixelBuffer(512, 512); }
- ~PixelBufferWrapper() { delete pbuffer; }
- QPaintDevice *realPaintDevice() { return pbuffer; }
-
- QGLPixelBuffer *pbuffer;
-};
-
-
-class FrameBufferObjectWrapper : public Device
-{
-public:
- FrameBufferObjectWrapper() {
- widget.makeCurrent();
- fbo = new QGLFramebufferObject(512, 512);
- widget.doneCurrent();
- }
- ~FrameBufferObjectWrapper() { delete fbo; }
- QPaintDevice *realPaintDevice() { return fbo; }
- void prepareDevice() { widget.makeCurrent(); }
-
- ThreadSafeGLWidget widget;
- QGLFramebufferObject *fbo;
-};
-
-
-class ThreadPainter : public QObject
-{
- Q_OBJECT
-public:
- ThreadPainter(Device *pd) : device(pd), fail(true) {
- pixmap = QPixmap(40, 40);
- pixmap.fill(Qt::green);
- QPainter p(&pixmap);
- p.drawLine(0, 0, 40, 40);
- p.drawLine(0, 40, 40, 0);
- }
-
-public slots:
- void draw() {
- bool beginFailed = false;
- QTime time;
- time.start();
- int rotAngle = 10;
- device->prepareDevice();
- QPaintDevice *paintDevice = device->realPaintDevice();
- QSize s(paintDevice->width(), paintDevice->height());
- while (time.elapsed() < RUNNING_TIME) {
- QPainter p;
- if (!p.begin(paintDevice)) {
- beginFailed = true;
- break;
- }
- p.translate(s.width()/2, s.height()/2);
- p.rotate(rotAngle);
- p.translate(-s.width()/2, -s.height()/2);
- p.fillRect(0, 0, s.width(), s.height(), Qt::red);
- QRect rect(QPoint(0, 0), s);
- p.drawPixmap(10, 10, pixmap);
- p.drawTiledPixmap(50, 50, 100, 100, pixmap);
- p.drawText(rect.center(), "This is a piece of text");
- p.end();
- rotAngle += 2;
- QThread::msleep(20);
- }
-
- fail = beginFailed;
- QThread::currentThread()->quit();
- }
-
- bool failed() { return fail; }
-
-private:
- QPixmap pixmap;
- Device *device;
- bool fail;
-};
-
-template <class T>
-class PaintThreadManager
-{
-public:
- PaintThreadManager(int count) : numThreads(count)
- {
- for (int i=0; i<numThreads; ++i) {
- devices.append(new T);
- threads.append(new QThread);
- painters.append(new ThreadPainter(devices.at(i)));
- painters.at(i)->moveToThread(threads.at(i));
- painters.at(i)->connect(threads.at(i), SIGNAL(started()), painters.at(i), SLOT(draw()));
- }
- }
-
- ~PaintThreadManager() {
- qDeleteAll(threads);
- qDeleteAll(painters);
- qDeleteAll(devices);
- }
-
-
- void start() {
- for (int i=0; i<numThreads; ++i)
- threads.at(i)->start();
- }
-
- bool areRunning() {
- bool running = false;
- for (int i=0; i<numThreads; ++i){
- if (threads.at(i)->isRunning())
- running = true;
- }
-
- return running;
- }
-
- bool failed() {
- for (int i=0; i<numThreads; ++i) {
- if (painters.at(i)->failed())
- return true;
- }
-
- return false;
- }
-
-private:
- QList<QThread *> threads;
- QList<Device *> devices;
- QList<ThreadPainter *> painters;
- int numThreads;
-};
-
-/*
- This test uses QPainter to draw onto different QGLWidgets in
- different threads at the same time. The ThreadSafeGLWidget is
- necessary to handle paint and resize events that might come from
- the main thread at any time while the test is running. The resize
- and paint events would cause makeCurrent() calls to be issued from
- within the QGLWidget while the widget's context was current in
- another thread, which would cause errors.
-*/
-void tst_QGLThreads::painterOnGLWidgetInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll);
-#endif
- if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) ||
- (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) {
- QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll);
- }
-
- PaintThreadManager<GLWidgetWrapper> painterThreads(5);
- painterThreads.start();
-
- while (painterThreads.areRunning()) {
- qApp->processEvents();
- QThread::msleep(100);
- }
- QVERIFY(!painterThreads.failed());
-}
-
-/*
- This test uses QPainter to draw onto different QPixmaps in
- different threads at the same time.
-*/
-void tst_QGLThreads::painterOnPixmapInThread()
-{
-#ifdef Q_WS_X11
- QSKIP("Drawing text in threads onto X11 drawables currently crashes on some X11 servers.", SkipAll);
-#endif
- PaintThreadManager<PixmapWrapper> painterThreads(5);
- painterThreads.start();
-
- while (painterThreads.areRunning()) {
- qApp->processEvents();
- QThread::msleep(100);
- }
- QVERIFY(!painterThreads.failed());
-}
-
-/* This test uses QPainter to draw onto different QGLPixelBuffer
- objects in different threads at the same time.
-*/
-void tst_QGLThreads::painterOnPboInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll);
-#endif
- if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) ||
- (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) {
- QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll);
- return;
- }
-
- if (!QGLPixelBuffer::hasOpenGLPbuffers()) {
- QSKIP("This system doesn't support pbuffers.", SkipAll);
- return;
- }
-
- PaintThreadManager<PixelBufferWrapper> painterThreads(5);
- painterThreads.start();
-
- while (painterThreads.areRunning()) {
- qApp->processEvents();
- QThread::msleep(100);
- }
- QVERIFY(!painterThreads.failed());
-}
-
-/* This test uses QPainter to draw onto different
- QGLFramebufferObjects (bound in a QGLWidget's context) in different
- threads at the same time.
-*/
-void tst_QGLThreads::painterOnFboInThread()
-{
-#ifdef Q_OS_MAC
- QSKIP("OpenGL threading tests are currently disabled on Mac as they were causing reboots", SkipAll);
-#endif
- if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) ||
- (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) {
- QSKIP("The OpenGL based threaded QPainter tests requires OpenGL/ES 2.0.", SkipAll);
- return;
- }
-
- if (!QGLFramebufferObject::hasOpenGLFramebufferObjects()) {
- QSKIP("This system doesn't support framebuffer objects.", SkipAll);
- return;
- }
-
- PaintThreadManager<FrameBufferObjectWrapper> painterThreads(5);
- painterThreads.start();
-
- while (painterThreads.areRunning()) {
- qApp->processEvents();
- QThread::msleep(100);
- }
- QVERIFY(!painterThreads.failed());
-}
-
-int main(int argc, char **argv)
-{
- QApplication::setAttribute(Qt::AA_X11InitThreads);
- QApplication app(argc, argv);
- QTEST_DISABLE_KEYPAD_NAVIGATION \
-
- tst_QGLThreads tc;
- return QTest::qExec(&tc, argc, argv);
-}
-
-#include "tst_qglthreads.moc"