summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dist/changes-5.0.09
-rw-r--r--src/opengl/qgl.cpp45
-rw-r--r--src/opengl/qgl.h4
-rw-r--r--src/opengl/qgl_p.h9
-rw-r--r--src/opengl/qgl_qpa.cpp11
-rw-r--r--src/opengl/qglpaintdevice.cpp7
-rw-r--r--src/opengl/qglpixelbuffer.cpp29
-rw-r--r--src/opengl/qglpixelbuffer.h2
-rw-r--r--src/opengl/qglpixelbuffer_p.h2
-rw-r--r--tests/auto/opengl/qglthreads/qglthreads.pro5
-rw-r--r--tests/auto/opengl/qglthreads/tst_qglthreads.cpp103
11 files changed, 184 insertions, 42 deletions
diff --git a/dist/changes-5.0.0 b/dist/changes-5.0.0
index 056b7506f0..c76f216fb5 100644
--- a/dist/changes-5.0.0
+++ b/dist/changes-5.0.0
@@ -676,6 +676,15 @@ QtOpenGL
which were deprecated in Qt 4 have been removed.
* Previously deprecated default value listBase parameter has been removed from
both QGLWidget::renderText() functions.
+* In order to ensure support on more platforms, stricter requirements have been
+ introduced for doing threaded OpenGL. First, you must call makeCurrent() at
+ least once per swapBuffers() call, so that the platform has a chance to
+ synchronize resizes to the OpenGL surface. Second, before doing makeCurrent()
+ or swapBuffers() in a separate thread, you must call
+ QGLContext::moveToThread(QThread *) to explicitly let Qt know in which thread
+ a QGLContext is currently being used. You also need to make sure that the
+ context is not current in the current thread before moving it to a different
+ thread.
QtScript
--------
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index c94c8f550e..583ecb69a8 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -3127,6 +3127,19 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context)
}
/*!
+ Moves the QGLContext to the given \a thread.
+
+ Enables calling swapBuffers() and makeCurrent() on the context in
+ the given thread.
+*/
+void QGLContext::moveToThread(QThread *thread)
+{
+ Q_D(QGLContext);
+ if (d->guiGlContext)
+ d->guiGlContext->moveToThread(thread);
+}
+
+/*!
\fn bool QGLContext::chooseContext(const QGLContext* shareContext = 0)
This semi-internal function is called by create(). It creates a
@@ -3195,16 +3208,18 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context)
In some very rare cases the underlying call may fail. If this
occurs an error message is output to stderr.
+
+ If you call this from a thread other than the main UI thread,
+ make sure you've first pushed the context to the relevant thread
+ from the UI thread using moveToThread().
*/
/*!
\fn void QGLContext::swapBuffers() const
- Swaps the screen contents with an off-screen buffer. Only works if
- the context is in double buffer mode.
-
- \sa QGLFormat::setDoubleBuffer()
+ Call this to finish a frame of OpenGL rendering, and make sure to
+ call makeCurrent() again before you begin a new frame.
*/
@@ -3362,13 +3377,18 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context)
1. Call doneCurrent() in the main thread when the rendering is
finished.
- 2. Notify the swapping thread that it can grab the context.
+ 2. Call QGLContext::moveToThread(swapThread) to transfer ownership
+ of the context to the swapping thread.
- 3. Make the rendering context current in the swapping thread with
+ 3. Notify the swapping thread that it can grab the context.
+
+ 4. Make the rendering context current in the swapping thread with
makeCurrent() and then call swapBuffers().
- 4. Call doneCurrent() in the swapping thread and notify the main
- thread that swapping is done.
+ 5. Call doneCurrent() in the swapping thread.
+
+ 6. Call QGLContext::moveToThread(qApp->thread()) and notify the
+ main thread that swapping is done.
Doing this will free up the main thread so that it can continue
with, for example, handling UI events or network requests. Even if
@@ -3400,7 +3420,10 @@ void QGLContextPrivate::setCurrentContext(QGLContext *context)
QGLWidgets can only be created in the main GUI thread. This means
a call to doneCurrent() is necessary to release the GL context
from the main thread, before the widget can be drawn into by
- another thread. Also, the main GUI thread will dispatch resize and
+ another thread. You then need to call QGLContext::moveToThread()
+ to transfer ownership of the context to the thread in which you
+ want to make it current.
+ Also, the main GUI thread will dispatch resize and
paint events to a QGLWidget when the widget is resized, or parts
of it becomes exposed or needs redrawing. It is therefore
necessary to handle those events because the default
@@ -3749,7 +3772,7 @@ void QGLWidget::setFormat(const QGLFormat &format)
/*!
- \fn const QGLContext *QGLWidget::context() const
+ \fn QGLContext *QGLWidget::context() const
Returns the context of this widget.
@@ -4483,7 +4506,7 @@ QGLFormat QGLWidget::format() const
return d->glcx->format();
}
-const QGLContext *QGLWidget::context() const
+QGLContext *QGLWidget::context() const
{
Q_D(const QGLWidget);
return d->glcx;
diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h
index ab2fd8d203..1d21b42cd5 100644
--- a/src/opengl/qgl.h
+++ b/src/opengl/qgl.h
@@ -281,6 +281,8 @@ public:
QGLFormat requestedFormat() const;
void setFormat(const QGLFormat& format);
+ void moveToThread(QThread *thread);
+
virtual void makeCurrent();
virtual void doneCurrent();
@@ -413,7 +415,7 @@ public:
QGLFormat format() const;
void setFormat(const QGLFormat& format);
- const QGLContext* context() const;
+ QGLContext* context() const;
void setContext(QGLContext* context, const QGLContext* shareContext = 0,
bool deleteOldContext = true);
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index df099ea281..904f3c1a3e 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -380,19 +380,18 @@ class Q_OPENGL_EXPORT QGLTextureDestroyer : public QObject
Q_OBJECT
public:
QGLTextureDestroyer() : QObject() {
- qRegisterMetaType<GLuint>();
- connect(this, SIGNAL(freeTexture(QGLContext *, QPlatformPixmap *, GLuint)),
- this, SLOT(freeTexture_slot(QGLContext *, QPlatformPixmap *, GLuint)));
+ connect(this, SIGNAL(freeTexture(QGLContext *, QPlatformPixmap *, quint32)),
+ this, SLOT(freeTexture_slot(QGLContext *, QPlatformPixmap *, quint32)));
}
void emitFreeTexture(QGLContext *context, QPlatformPixmap *boundPixmap, GLuint id) {
emit freeTexture(context, boundPixmap, id);
}
Q_SIGNALS:
- void freeTexture(QGLContext *context, QPlatformPixmap *boundPixmap, GLuint id);
+ void freeTexture(QGLContext *context, QPlatformPixmap *boundPixmap, quint32 id);
private slots:
- void freeTexture_slot(QGLContext *context, QPlatformPixmap *boundPixmap, GLuint id) {
+ void freeTexture_slot(QGLContext *context, QPlatformPixmap *boundPixmap, quint32 id) {
Q_UNUSED(boundPixmap);
QGLShareContextScope scope(context);
glDeleteTextures(1, &id);
diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp
index f52beceaae..ba07f6121c 100644
--- a/src/opengl/qgl_qpa.cpp
+++ b/src/opengl/qgl_qpa.cpp
@@ -186,9 +186,14 @@ void QGLContext::reset()
d->initDone = false;
QGLContextGroup::removeShare(this);
if (d->guiGlContext) {
- if (d->ownContext)
- delete d->guiGlContext;
- else
+ if (QOpenGLContext::currentContext() == d->guiGlContext)
+ doneCurrent();
+ if (d->ownContext) {
+ if (d->guiGlContext->thread() == QThread::currentThread())
+ delete d->guiGlContext;
+ else
+ d->guiGlContext->deleteLater();
+ } else
d->guiGlContext->setQGLContextHandle(0,0);
d->guiGlContext = 0;
}
diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp
index 5aa125f816..e870e45e15 100644
--- a/src/opengl/qglpaintdevice.cpp
+++ b/src/opengl/qglpaintdevice.cpp
@@ -43,6 +43,7 @@
#include <private/qgl_p.h>
#include <private/qglpixelbuffer_p.h>
#include <private/qglframebufferobject_p.h>
+#include <qopenglfunctions.h>
QT_BEGIN_NAMESPACE
@@ -90,7 +91,7 @@ void QGLPaintDevice::beginPaint()
if (m_previousFBO != m_thisFBO) {
ctx->d_ptr->current_fbo = m_thisFBO;
- glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
+ ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
}
// Set the default fbo for the context to m_thisFBO so that
@@ -108,7 +109,7 @@ void QGLPaintDevice::ensureActiveTarget()
if (ctx->d_ptr->current_fbo != m_thisFBO) {
ctx->d_ptr->current_fbo = m_thisFBO;
- glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
+ ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_thisFBO);
}
ctx->d_ptr->default_fbo = m_thisFBO;
@@ -120,7 +121,7 @@ void QGLPaintDevice::endPaint()
QGLContext *ctx = context();
if (m_previousFBO != ctx->d_func()->current_fbo) {
ctx->d_ptr->current_fbo = m_previousFBO;
- glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO);
+ ctx->contextHandle()->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_previousFBO);
}
ctx->d_ptr->default_fbo = 0;
diff --git a/src/opengl/qglpixelbuffer.cpp b/src/opengl/qglpixelbuffer.cpp
index a5e748a1e7..dd13ef24eb 100644
--- a/src/opengl/qglpixelbuffer.cpp
+++ b/src/opengl/qglpixelbuffer.cpp
@@ -100,6 +100,7 @@
#include "gl2paintengineex/qpaintengineex_opengl2_p.h"
+#include <qglframebufferobject.h>
#include <qglpixelbuffer.h>
#include <private/qglpixelbuffer_p.h>
#include <private/qfont_p.h>
@@ -115,11 +116,23 @@ QGLContext* QGLPBufferGLPaintDevice::context() const
return pbuf->d_func()->qctx;
}
-void QGLPBufferGLPaintDevice::endPaint() {
+void QGLPBufferGLPaintDevice::beginPaint()
+{
+ pbuf->makeCurrent();
+ QGLPaintDevice::beginPaint();
+}
+
+void QGLPBufferGLPaintDevice::endPaint()
+{
glFlush();
QGLPaintDevice::endPaint();
}
+void QGLPBufferGLPaintDevice::setFbo(GLuint fbo)
+{
+ m_thisFBO = fbo;
+}
+
void QGLPBufferGLPaintDevice::setPBuffer(QGLPixelBuffer* pb)
{
pbuf = pb;
@@ -221,6 +234,7 @@ bool QGLPixelBuffer::makeCurrent()
format.setSamples(d->req_format.samples());
d->fbo = new QOpenGLFramebufferObject(d->req_size, format);
d->fbo->bind();
+ d->glDevice.setFbo(d->fbo->handle());
glViewport(0, 0, d->req_size.width(), d->req_size.height());
}
return true;
@@ -242,6 +256,15 @@ bool QGLPixelBuffer::doneCurrent()
}
/*!
+ Returns the context of this pixelbuffer.
+*/
+QGLContext *QGLPixelBuffer::context() const
+{
+ Q_D(const QGLPixelBuffer);
+ return d->qctx;
+}
+
+/*!
\fn GLuint QGLPixelBuffer::generateDynamicTexture() const
Generates and binds a 2D GL texture that is the same size as the
@@ -366,6 +389,8 @@ QImage QGLPixelBuffer::toImage() const
return QImage();
const_cast<QGLPixelBuffer *>(this)->makeCurrent();
+ if (d->fbo)
+ d->fbo->bind();
return qt_gl_read_framebuffer(d->req_size, d->format.alpha(), true);
}
@@ -615,7 +640,7 @@ GLuint QGLPixelBuffer::generateDynamicTexture() const
bool QGLPixelBuffer::hasOpenGLPbuffers()
{
- return QOpenGLFramebufferObject::hasOpenGLFramebufferObjects();
+ return QGLFramebufferObject::hasOpenGLFramebufferObjects();
}
QT_END_NAMESPACE
diff --git a/src/opengl/qglpixelbuffer.h b/src/opengl/qglpixelbuffer.h
index 58cd470d3d..f597a48695 100644
--- a/src/opengl/qglpixelbuffer.h
+++ b/src/opengl/qglpixelbuffer.h
@@ -66,6 +66,8 @@ public:
bool makeCurrent();
bool doneCurrent();
+ QGLContext *context() const;
+
GLuint generateDynamicTexture() const;
bool bindToDynamicTexture(GLuint texture);
void releaseFromDynamicTexture();
diff --git a/src/opengl/qglpixelbuffer_p.h b/src/opengl/qglpixelbuffer_p.h
index fd20cee07a..caa2e2f7d1 100644
--- a/src/opengl/qglpixelbuffer_p.h
+++ b/src/opengl/qglpixelbuffer_p.h
@@ -68,8 +68,10 @@ public:
virtual QPaintEngine* paintEngine() const {return pbuf->paintEngine();}
virtual QSize size() const {return pbuf->size();}
virtual QGLContext* context() const;
+ virtual void beginPaint();
virtual void endPaint();
void setPBuffer(QGLPixelBuffer* pb);
+ void setFbo(GLuint fbo);
private:
QGLPixelBuffer* pbuf;
};
diff --git a/tests/auto/opengl/qglthreads/qglthreads.pro b/tests/auto/opengl/qglthreads/qglthreads.pro
index 754f494cfa..d5cbd0d9ed 100644
--- a/tests/auto/opengl/qglthreads/qglthreads.pro
+++ b/tests/auto/opengl/qglthreads/qglthreads.pro
@@ -1,7 +1,7 @@
CONFIG += testcase
TARGET = tst_qglthreads
requires(contains(QT_CONFIG,opengl))
-QT += opengl widgets testlib
+QT += opengl widgets testlib gui-private core-private
HEADERS += tst_qglthreads.h
SOURCES += tst_qglthreads.cpp
@@ -10,5 +10,6 @@ x11 {
LIBS += $$QMAKE_LIBS_X11
}
-CONFIG+=insignificant_test # QTBUG-22560
DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0
+
+win32:CONFIG+=insignificant_test # QTBUG-28264
diff --git a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp
index 267e3260f1..8535f177cd 100644
--- a/tests/auto/opengl/qglthreads/tst_qglthreads.cpp
+++ b/tests/auto/opengl/qglthreads/tst_qglthreads.cpp
@@ -42,6 +42,8 @@
#include <QtTest/QtTest>
#include <QtCore/QtCore>
#include <QtGui/QtGui>
+#include <private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
#include <QtWidgets/QApplication>
#include <QtOpenGL/QtOpenGL>
#include "tst_qglthreads.h"
@@ -74,7 +76,8 @@ class SwapThread : public QThread
Q_OBJECT
public:
SwapThread(QGLWidget *widget)
- : m_widget(widget)
+ : m_context(widget->context())
+ , m_swapTriggered(false)
{
moveToThread(this);
}
@@ -84,25 +87,48 @@ public:
time.start();
while (time.elapsed() < RUNNING_TIME) {
lock();
- wait();
+ waitForReadyToSwap();
- m_widget->makeCurrent();
- m_widget->swapBuffers();
- m_widget->doneCurrent();
+ m_context->makeCurrent();
+ m_context->swapBuffers();
+ m_context->doneCurrent();
+
+ m_context->moveToThread(qApp->thread());
+
+ signalSwapDone();
unlock();
}
+
+ m_swapTriggered = false;
}
void lock() { m_mutex.lock(); }
void unlock() { m_mutex.unlock(); }
- void wait() { m_wait_condition.wait(&m_mutex); }
- void notify() { m_wait_condition.wakeAll(); }
+ void waitForSwapDone() { if (m_swapTriggered) m_swapDone.wait(&m_mutex); }
+ void waitForReadyToSwap() { if (!m_swapTriggered) m_readyToSwap.wait(&m_mutex); }
+
+ void signalReadyToSwap()
+ {
+ if (!isRunning())
+ return;
+ m_readyToSwap.wakeAll();
+ m_swapTriggered = true;
+ }
+
+ void signalSwapDone()
+ {
+ m_swapTriggered = false;
+ m_swapDone.wakeAll();
+ }
private:
- QGLWidget *m_widget;
+ QGLContext *m_context;
QMutex m_mutex;
- QWaitCondition m_wait_condition;
+ QWaitCondition m_readyToSwap;
+ QWaitCondition m_swapDone;
+
+ bool m_swapTriggered;
};
class ForegroundWidget : public QGLWidget
@@ -117,6 +143,8 @@ public:
void paintEvent(QPaintEvent *)
{
m_thread->lock();
+ m_thread->waitForSwapDone();
+
makeCurrent();
QPainter p(this);
p.fillRect(rect(), QColor(rand() % 256, rand() % 256, rand() % 256));
@@ -125,7 +153,12 @@ public:
p.drawText(rect(), Qt::AlignCenter, "This is an autotest");
p.end();
doneCurrent();
- m_thread->notify();
+
+ if (m_thread->isRunning()) {
+ context()->moveToThread(m_thread);
+ m_thread->signalReadyToSwap();
+ }
+
m_thread->unlock();
update();
@@ -140,6 +173,8 @@ public:
void tst_QGLThreads::swapInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
QGLFormat format;
format.setSwapInterval(1);
ForegroundWidget widget(format);
@@ -176,10 +211,12 @@ class CreateAndUploadThread : public QThread
{
Q_OBJECT
public:
- CreateAndUploadThread(QGLWidget *shareWidget)
+ CreateAndUploadThread(QGLWidget *shareWidget, QSemaphore *semaphore)
+ : m_semaphore(semaphore)
{
m_gl = new QGLWidget(0, shareWidget);
moveToThread(this);
+ m_gl->context()->moveToThread(this);
}
~CreateAndUploadThread()
@@ -203,6 +240,8 @@ public:
p.end();
m_gl->bindTexture(image, GL_TEXTURE_2D, GL_RGBA, QGLContext::InternalBindOption);
+ m_semaphore->acquire(1);
+
createdAndUploaded(image);
}
}
@@ -212,12 +251,18 @@ signals:
private:
QGLWidget *m_gl;
+ QSemaphore *m_semaphore;
};
class TextureDisplay : public QGLWidget
{
Q_OBJECT
public:
+ TextureDisplay(QSemaphore *semaphore)
+ : m_semaphore(semaphore)
+ {
+ }
+
void paintEvent(QPaintEvent *) {
QPainter p(this);
for (int i=0; i<m_images.size(); ++i) {
@@ -232,6 +277,8 @@ public slots:
m_images << image;
m_positions << QPoint(-rand() % width() / 2, -rand() % height() / 2);
+ m_semaphore->release(1);
+
if (m_images.size() > 100) {
m_images.takeFirst();
m_positions.takeFirst();
@@ -241,12 +288,19 @@ public slots:
private:
QList <QImage> m_images;
QList <QPoint> m_positions;
+
+ QSemaphore *m_semaphore;
};
void tst_QGLThreads::textureUploadInThread()
{
- TextureDisplay display;
- CreateAndUploadThread thread(&display);
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
+
+ // prevent producer thread from queuing up too many images
+ QSemaphore semaphore(100);
+ TextureDisplay display(&semaphore);
+ CreateAndUploadThread thread(&display, &semaphore);
connect(&thread, SIGNAL(createdAndUploaded(QImage)), &display, SLOT(receiveImage(QImage)));
@@ -362,10 +416,9 @@ public:
time.start();
failure = false;
- m_widget->makeCurrent();
-
while (time.elapsed() < RUNNING_TIME && !failure) {
+ m_widget->makeCurrent();
m_widget->mutex.lock();
QSize s = m_widget->newSize;
@@ -416,6 +469,8 @@ void tst_QGLThreads::renderInThread_data()
void tst_QGLThreads::renderInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
QFETCH(bool, resize);
QFETCH(bool, update);
@@ -428,6 +483,8 @@ void tst_QGLThreads::renderInThread()
QVERIFY(QTest::qWaitForWindowExposed(&widget));
widget.doneCurrent();
+ widget.context()->moveToThread(&thread);
+
thread.start();
int value = 10;
@@ -451,6 +508,7 @@ public:
virtual ~Device() {}
virtual QPaintDevice *realPaintDevice() = 0;
virtual void prepareDevice() {}
+ virtual void moveToThread(QThread *) {}
};
class GLWidgetWrapper : public Device
@@ -463,6 +521,7 @@ public:
widget.doneCurrent();
}
QPaintDevice *realPaintDevice() { return &widget; }
+ void moveToThread(QThread *thread) { widget.context()->moveToThread(thread); }
ThreadSafeGLWidget widget;
};
@@ -483,6 +542,7 @@ public:
PixelBufferWrapper() { pbuffer = new QGLPixelBuffer(512, 512); }
~PixelBufferWrapper() { delete pbuffer; }
QPaintDevice *realPaintDevice() { return pbuffer; }
+ void moveToThread(QThread *thread) { pbuffer->context()->moveToThread(thread); }
QGLPixelBuffer *pbuffer;
};
@@ -499,6 +559,7 @@ public:
~FrameBufferObjectWrapper() { delete fbo; }
QPaintDevice *realPaintDevice() { return fbo; }
void prepareDevice() { widget.makeCurrent(); }
+ void moveToThread(QThread *thread) { widget.context()->moveToThread(thread); }
ThreadSafeGLWidget widget;
QGLFramebufferObject *fbo;
@@ -545,6 +606,8 @@ public slots:
QThread::msleep(20);
}
+ device->moveToThread(qApp->thread());
+
fail = beginFailed;
QThread::currentThread()->quit();
}
@@ -569,6 +632,7 @@ public:
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()));
+ devices.at(i)->moveToThread(threads.at(i));
}
}
@@ -621,6 +685,8 @@ private:
*/
void tst_QGLThreads::painterOnGLWidgetInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
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.");
@@ -642,6 +708,9 @@ void tst_QGLThreads::painterOnGLWidgetInThread()
*/
void tst_QGLThreads::painterOnPixmapInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL)
+ || !QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps))
+ QSKIP("No platformsupport for ThreadedOpenGL or ThreadedPixmaps");
#ifdef Q_WS_X11
QSKIP("Drawing text in threads onto X11 drawables currently crashes on some X11 servers.");
#endif
@@ -660,6 +729,8 @@ void tst_QGLThreads::painterOnPixmapInThread()
*/
void tst_QGLThreads::painterOnPboInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
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.");
@@ -685,6 +756,8 @@ void tst_QGLThreads::painterOnPboInThread()
*/
void tst_QGLThreads::painterOnFboInThread()
{
+ if (!QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL))
+ QSKIP("No platformsupport for ThreadedOpenGL");
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.");