summaryrefslogtreecommitdiffstats
path: root/tests/auto/gui/qopengl/tst_qopengl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/gui/qopengl/tst_qopengl.cpp')
-rw-r--r--tests/auto/gui/qopengl/tst_qopengl.cpp283
1 files changed, 269 insertions, 14 deletions
diff --git a/tests/auto/gui/qopengl/tst_qopengl.cpp b/tests/auto/gui/qopengl/tst_qopengl.cpp
index 63fe8b9693..6d83defdeb 100644
--- a/tests/auto/gui/qopengl/tst_qopengl.cpp
+++ b/tests/auto/gui/qopengl/tst_qopengl.cpp
@@ -43,6 +43,8 @@
#include <QtGui/private/qopenglcontext_p.h>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLFunctions_4_2_Core>
+#include <QtGui/QOpenGLVertexArrayObject>
#include <QtGui/QOpenGLPaintDevice>
#include <QtGui/QPainter>
#include <QtGui/QScreen>
@@ -51,12 +53,25 @@
#include <QtGui/QGenericMatrix>
#include <QtGui/QMatrix4x4>
#include <QtGui/private/qopengltextureblitter_p.h>
-
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
#include <QtTest/QtTest>
#include <QSignalSpy>
+#ifdef USE_GLX
+// Must be included last due to the X11 types
+#include <QtPlatformHeaders/QGLXNativeContext>
+#endif
+
+#if defined(Q_OS_WIN32) && !defined(QT_OPENGL_ES_2)
+#include <QtPlatformHeaders/QWGLNativeContext>
+#endif
+
+Q_DECLARE_METATYPE(QImage::Format)
+
class tst_QOpenGL : public QObject
{
Q_OBJECT
@@ -74,6 +89,8 @@ private slots:
void fboTextureOwnership();
void fboRendering_data();
void fboRendering();
+ void fboRenderingRGB30_data();
+ void fboRenderingRGB30();
void fboHandleNulledAfterContextDestroyed();
void openGLPaintDevice_data();
void openGLPaintDevice();
@@ -85,6 +102,16 @@ private slots:
void textureblitterPartOriginTopLeftSourceRectTransform();
void textureblitterFullTargetRectTransform();
void textureblitterPartTargetRectTransform();
+
+#ifdef USE_GLX
+ void glxContextWrap();
+#endif
+
+#if defined(Q_OS_WIN32) && !defined(QT_OPENGL_ES_2)
+ void wglContextWrap();
+#endif
+
+ void vaoCreate();
};
struct SharedResourceTracker
@@ -448,9 +475,9 @@ void tst_QOpenGL::fboSimpleRendering()
QVERIFY(fbo->bind());
- glClearColor(1.0, 0.0, 0.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glFinish();
+ ctx.functions()->glClearColor(1.0, 0.0, 0.0, 1.0);
+ ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
+ ctx.functions()->glFinish();
const QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
QCOMPARE(fb.size(), size);
@@ -494,9 +521,9 @@ void tst_QOpenGL::fboTextureOwnership()
fbo->bind();
QVERIFY(fbo->texture() != 0 && fbo->texture() != texture);
- glClearColor(1.0, 0.0, 0.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glFinish();
+ ctx.functions()->glClearColor(1.0, 0.0, 0.0, 1.0);
+ ctx.functions()->glClear(GL_COLOR_BUFFER_BIT);
+ ctx.functions()->glFinish();
QImage fb = fbo->toImage().convertToFormat(QImage::Format_RGB32);
QImage reference(fb.size(), QImage::Format_RGB32);
@@ -504,7 +531,7 @@ void tst_QOpenGL::fboTextureOwnership()
QFUZZY_COMPARE_IMAGES(fb, reference);
- glDeleteTextures(1, &texture);
+ ctx.functions()->glDeleteTextures(1, &texture);
delete fbo;
}
@@ -539,7 +566,7 @@ void tst_QOpenGL::fboRendering()
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
- // Uncomplicate things by using NPOT:
+ // Uncomplicate things by using POT:
const QSize size(256, 128);
QOpenGLFramebufferObject fbo(size, fboFormat);
@@ -563,6 +590,111 @@ void tst_QOpenGL::fboRendering()
qt_opengl_check_test_pattern(fb);
}
+void tst_QOpenGL::fboRenderingRGB30_data()
+{
+ common_data();
+}
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
+#ifndef GL_FRAMEBUFFER_RENDERABLE
+#define GL_FRAMEBUFFER_RENDERABLE 0x8289
+#endif
+
+#ifndef GL_FULL_SUPPORT
+#define GL_FULL_SUPPORT 0x82B7
+#endif
+
+void tst_QOpenGL::fboRenderingRGB30()
+{
+#if defined(Q_OS_LINUX) && defined(Q_CC_GNU) && !defined(__x86_64__)
+ QSKIP("QTBUG-22617");
+#endif
+
+ QFETCH(int, surfaceClass);
+ QScopedPointer<QSurface> surface(createSurface(surfaceClass));
+
+ QOpenGLContext ctx;
+ QVERIFY(ctx.create());
+
+ QVERIFY(ctx.makeCurrent(surface.data()));
+
+ if (!QOpenGLFramebufferObject::hasOpenGLFramebufferObjects())
+ QSKIP("QOpenGLFramebufferObject not supported on this platform");
+
+ if (ctx.format().majorVersion() < 3)
+ QSKIP("An internal RGB30_A2 format is not guaranteed on this platform");
+
+#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2)
+ // NVidia currently only supports RGB30 and RGB30_A2 in their Quadro drivers,
+ // but they do provide an extension for querying the support. We use the query
+ // in case they implement the required formats later.
+ if (!ctx.isOpenGLES() && ctx.format().majorVersion() >= 4) {
+ GLint value = -1;
+ QOpenGLFunctions_4_2_Core* vFuncs = ctx.versionFunctions<QOpenGLFunctions_4_2_Core>();
+ if (vFuncs && vFuncs->initializeOpenGLFunctions()) {
+ vFuncs->glGetInternalformativ(GL_TEXTURE_2D, GL_RGB10_A2, GL_FRAMEBUFFER_RENDERABLE, 1, &value);
+ if (value != GL_FULL_SUPPORT)
+ QSKIP("The required RGB30_A2 format is not supported by this driver");
+ }
+ }
+#endif
+
+ // No multisample with combined depth/stencil attachment:
+ QOpenGLFramebufferObjectFormat fboFormat;
+ fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ fboFormat.setInternalTextureFormat(GL_RGB10_A2);
+
+ // Uncomplicate things by using POT:
+ const QSize size(256, 128);
+ QOpenGLFramebufferObject fbo(size, fboFormat);
+
+ if (fbo.attachment() != QOpenGLFramebufferObject::CombinedDepthStencil)
+ QSKIP("FBOs missing combined depth~stencil support");
+
+ QVERIFY(fbo.bind());
+
+ QPainter fboPainter;
+ QOpenGLPaintDevice device(fbo.width(), fbo.height());
+ bool painterBegun = fboPainter.begin(&device);
+ QVERIFY(painterBegun);
+
+ qt_opengl_draw_test_pattern(&fboPainter, fbo.width(), fbo.height());
+
+ fboPainter.end();
+
+ QImage fb = fbo.toImage();
+ QCOMPARE(fb.format(), QImage::Format_A2BGR30_Premultiplied);
+ QCOMPARE(fb.size(), size);
+
+ qt_opengl_check_test_pattern(fb);
+
+ // Check rendering can handle color values below 1/256.
+ fboPainter.begin(&device);
+ fboPainter.fillRect(QRect(0, 0, 256, 128), QColor::fromRgbF(1.0/512, 1.0/512, 1.0/512));
+ fboPainter.end();
+ fb = fbo.toImage();
+ uint pixel = ((uint*)fb.bits())[0];
+ QVERIFY((pixel & 0x3f) > 0);
+ QVERIFY(((pixel >> 10) & 0x3f) > 0);
+ QVERIFY(((pixel >> 20) & 0x3f) > 0);
+
+ pixel = (3U << 30) | (2U << 20) | (2U << 10) | 2U;
+ fb.fill(pixel);
+
+ fboPainter.begin(&device);
+ fboPainter.setCompositionMode(QPainter::CompositionMode_Source);
+ fboPainter.drawImage(0, 0, fb);
+ fboPainter.end();
+ fb = fbo.toImage();
+ pixel = ((uint*)fb.bits())[0];
+ QVERIFY((pixel & 0x3f) > 0);
+ QVERIFY(((pixel >> 10) & 0x3f) > 0);
+ QVERIFY(((pixel >> 20) & 0x3f) > 0);
+}
+
void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
{
QWindow window;
@@ -591,7 +723,14 @@ void tst_QOpenGL::fboHandleNulledAfterContextDestroyed()
void tst_QOpenGL::openGLPaintDevice_data()
{
- common_data();
+ QTest::addColumn<int>("surfaceClass");
+ QTest::addColumn<QImage::Format>("imageFormat");
+
+ QTest::newRow("Using QWindow - RGB32") << int(QSurface::Window) << QImage::Format_RGB32;
+ QTest::newRow("Using QOffscreenSurface - RGB32") << int(QSurface::Offscreen) << QImage::Format_RGB32;
+ QTest::newRow("Using QOffscreenSurface - RGBx8888") << int(QSurface::Offscreen) << QImage::Format_RGBX8888;
+ QTest::newRow("Using QOffscreenSurface - RGB888") << int(QSurface::Offscreen) << QImage::Format_RGB888;
+ QTest::newRow("Using QOffscreenSurface - RGB16") << int(QSurface::Offscreen) << QImage::Format_RGB16;
}
void tst_QOpenGL::openGLPaintDevice()
@@ -601,6 +740,7 @@ void tst_QOpenGL::openGLPaintDevice()
#endif
QFETCH(int, surfaceClass);
+ QFETCH(QImage::Format, imageFormat);
QScopedPointer<QSurface> surface(createSurface(surfaceClass));
QOpenGLContext ctx;
@@ -613,7 +753,7 @@ void tst_QOpenGL::openGLPaintDevice()
const QSize size(128, 128);
- QImage image(size, QImage::Format_RGB32);
+ QImage image(size, imageFormat);
QPainter p(&image);
p.fillRect(0, 0, image.width() / 2, image.height() / 2, Qt::red);
p.fillRect(image.width() / 2, 0, image.width() / 2, image.height() / 2, Qt::green);
@@ -632,7 +772,7 @@ void tst_QOpenGL::openGLPaintDevice()
p.fillRect(0, image.height() / 2, image.width() / 2, image.height() / 2, Qt::white);
p.end();
- QImage actual = fbo.toImage().convertToFormat(QImage::Format_RGB32);
+ QImage actual = fbo.toImage().convertToFormat(imageFormat);
QCOMPARE(image.size(), actual.size());
QCOMPARE(image, actual);
@@ -641,7 +781,7 @@ void tst_QOpenGL::openGLPaintDevice()
p.drawImage(0, 0, image);
p.end();
- actual = fbo.toImage().convertToFormat(QImage::Format_RGB32);
+ actual = fbo.toImage().convertToFormat(imageFormat);
QCOMPARE(image.size(), actual.size());
QCOMPARE(image, actual);
@@ -650,7 +790,7 @@ void tst_QOpenGL::openGLPaintDevice()
p.fillRect(0, 0, image.width(), image.height(), QBrush(image));
p.end();
- actual = fbo.toImage().convertToFormat(QImage::Format_RGB32);
+ actual = fbo.toImage().convertToFormat(imageFormat);
QCOMPARE(image.size(), actual.size());
QCOMPARE(image, actual);
}
@@ -970,6 +1110,121 @@ void tst_QOpenGL::textureblitterPartTargetRectTransform()
QCOMPARE(targetBottomRight, expectedBottomRight);
}
+#ifdef USE_GLX
+void tst_QOpenGL::glxContextWrap()
+{
+ QWindow *window = new QWindow;
+ window->setSurfaceType(QWindow::OpenGLSurface);
+ window->setGeometry(0, 0, 10, 10);
+ window->show();
+ QTest::qWaitForWindowExposed(window);
+
+ QPlatformNativeInterface *nativeIf = QGuiApplicationPrivate::instance()->platformIntegration()->nativeInterface();
+ QVERIFY(nativeIf);
+
+ // Fetch a GLXContext.
+ QOpenGLContext *ctx0 = new QOpenGLContext;
+ ctx0->setFormat(window->format());
+ QVERIFY(ctx0->create());
+ QVariant v = ctx0->nativeHandle();
+ QVERIFY(!v.isNull());
+ QVERIFY(v.canConvert<QGLXNativeContext>());
+ GLXContext context = v.value<QGLXNativeContext>().context();
+ QVERIFY(context);
+
+ // Then create another QOpenGLContext wrapping it.
+ QOpenGLContext *ctx = new QOpenGLContext;
+ ctx->setNativeHandle(QVariant::fromValue<QGLXNativeContext>(QGLXNativeContext(context)));
+ QVERIFY(ctx->create());
+ QVERIFY(ctx->nativeHandle().value<QGLXNativeContext>().context() == context);
+ QVERIFY(nativeIf->nativeResourceForContext(QByteArrayLiteral("glxcontext"), ctx) == (void *) context);
+
+ QVERIFY(ctx->makeCurrent(window));
+ ctx->doneCurrent();
+
+ delete ctx;
+ delete ctx0;
+
+ delete window;
+}
+#endif // USE_GLX
+
+#if defined(Q_OS_WIN32) && !defined(QT_OPENGL_ES_2)
+void tst_QOpenGL::wglContextWrap()
+{
+ QScopedPointer<QOpenGLContext> ctx(new QOpenGLContext);
+ QVERIFY(ctx->create());
+ if (ctx->isOpenGLES())
+ QSKIP("Not applicable to EGL");
+
+ QScopedPointer<QWindow> window(new QWindow);
+ window->setSurfaceType(QWindow::OpenGLSurface);
+ window->setGeometry(0, 0, 256, 256);
+ window->show();
+ QTest::qWaitForWindowExposed(window.data());
+
+ QVariant v = ctx->nativeHandle();
+ QVERIFY(!v.isNull());
+ QVERIFY(v.canConvert<QWGLNativeContext>());
+ QWGLNativeContext nativeContext = v.value<QWGLNativeContext>();
+ QVERIFY(nativeContext.context());
+
+ // Now do a makeCurrent() do make sure the pixel format on the native
+ // window (the HWND we are going to retrieve below) is set.
+ QVERIFY(ctx->makeCurrent(window.data()));
+ ctx->doneCurrent();
+
+ HWND wnd = (HWND) qGuiApp->platformNativeInterface()->nativeResourceForWindow(QByteArrayLiteral("handle"), window.data());
+ QVERIFY(wnd);
+
+ QScopedPointer<QOpenGLContext> adopted(new QOpenGLContext);
+ adopted->setNativeHandle(QVariant::fromValue<QWGLNativeContext>(QWGLNativeContext(nativeContext.context(), wnd)));
+ QVERIFY(adopted->create());
+
+ // This tests two things: that a regular, non-adopted QOpenGLContext is
+ // able to return a QSurfaceFormat containing the real values after
+ // create(), and that the adopted context got the correct pixel format from
+ // window and was able to update its format accordingly.
+ QCOMPARE(adopted->format().version(), ctx->format().version());
+ QCOMPARE(adopted->format().profile(), ctx->format().profile());
+ QVERIFY(ctx->format().redBufferSize() > 0);
+ QCOMPARE(adopted->format().redBufferSize(), ctx->format().redBufferSize());
+ QVERIFY(ctx->format().greenBufferSize() > 0);
+ QCOMPARE(adopted->format().greenBufferSize(), ctx->format().greenBufferSize());
+ QVERIFY(ctx->format().blueBufferSize() > 0);
+ QCOMPARE(adopted->format().blueBufferSize(), ctx->format().blueBufferSize());
+ QVERIFY(ctx->format().depthBufferSize() > 0);
+ QCOMPARE(adopted->format().depthBufferSize(), ctx->format().depthBufferSize());
+ QVERIFY(ctx->format().stencilBufferSize() > 0);
+ QCOMPARE(adopted->format().stencilBufferSize(), ctx->format().stencilBufferSize());
+
+ // This must work since we are using the exact same window.
+ QVERIFY(adopted->makeCurrent(window.data()));
+ adopted->doneCurrent();
+}
+#endif // Q_OS_WIN32 && !QT_OPENGL_ES_2
+
+void tst_QOpenGL::vaoCreate()
+{
+ QScopedPointer<QSurface> surface(createSurface(QSurface::Window));
+ QOpenGLContext *ctx = new QOpenGLContext;
+ ctx->create();
+ ctx->makeCurrent(surface.data());
+
+ QOpenGLVertexArrayObject vao;
+ bool success = vao.create();
+ if (ctx->isOpenGLES()) {
+ if (ctx->format().majorVersion() >= 3 || ctx->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object")))
+ QVERIFY(success);
+ } else {
+ if (ctx->format().majorVersion() >= 3 || ctx->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object")))
+ QVERIFY(success);
+ }
+
+ vao.destroy();
+ ctx->doneCurrent();
+}
+
QTEST_MAIN(tst_QOpenGL)
#include "tst_qopengl.moc"