diff options
Diffstat (limited to 'tests/auto/gui/qopengl/tst_qopengl.cpp')
-rw-r--r-- | tests/auto/gui/qopengl/tst_qopengl.cpp | 283 |
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" |