diff options
author | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-05-07 15:33:47 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@theqtcompany.com> | 2016-05-08 20:03:24 +0000 |
commit | 3fe2ecccc96ef1d8243e0683853c5db8c6ed9ee0 (patch) | |
tree | 8a71bdc03443808cbb6fa4cc27ac34f8e9fd861c | |
parent | e3716cdf88a09109e368adc4f73fc52ff6325f83 (diff) |
D3D12: Massage tst_qquickwindow and some sg semantics
Change-Id: Ic4cc9ae5c1df2ab7e1da50ac414dc3d7f264e691
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
4 files changed, 87 insertions, 50 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp index 8a4fd678e7..b32bfe063a 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp @@ -117,4 +117,13 @@ void QSGD3D12RenderContext::setEngine(QSGD3D12Engine *engine) emit initialized(); } +void QSGD3D12RenderContext::ensureInitializedEmitted() +{ + if (!m_pendingInitialized) + return; + + m_pendingInitialized = false; + emit initialized(); +} + QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h index e2cd6e3182..86a300831d 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h +++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h @@ -70,8 +70,12 @@ public: void setEngine(QSGD3D12Engine *engine); QSGD3D12Engine *engine() { return m_engine; } + void ensureInitializedEmitted(); + void setInitializedPending() { m_pendingInitialized = true; } + private: QSGD3D12Engine *m_engine = nullptr; + bool m_pendingInitialized = false; }; QT_END_NAMESPACE diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp index fccb127c4f..9798f0ca66 100644 --- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp +++ b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp @@ -294,7 +294,26 @@ bool QSGD3D12RenderThread::event(QEvent *e) QSGD3D12SyncEvent *wme = static_cast<QSGD3D12SyncEvent *>(e); if (sleeping) stopEventProcessing = true; - if (!engine->window()) { + // One thread+engine for each window. However, the native window may + // change in some (quite artificial) cases, e.g. due to a hide - + // destroy - show on the QWindow. + bool needsWindow = !engine->window(); + if (engine->window() && engine->window() != wme->window->winId()) { + if (Q_UNLIKELY(debug_loop())) + qDebug("RT - WM_RequestSync - native window handle changes for active engine"); + engine->waitGPU(); + QQuickWindowPrivate::get(wme->window)->cleanupNodesOnShutdown(); + QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache(); + rc->invalidate(); + engine->releaseResources(); + needsWindow = true; + // Be nice and emit the rendercontext's initialized() later on at + // some point so that QQuickWindow::sceneGraphInitialized() behaves + // in a manner similar to GL. + rc->setInitializedPending(); + } + if (needsWindow) { + // Must only ever get here when there is no window or releaseResources() has been called. const int samples = wme->window->format().samples(); if (Q_UNLIKELY(debug_loop())) qDebug() << "RT - WM_RequestSync - initializing D3D12 engine" << wme->window @@ -302,7 +321,6 @@ bool QSGD3D12RenderThread::event(QEvent *e) engine->attachToWindow(wme->window->winId(), wme->size, wme->dpr, samples); } exposedWindow = wme->window; - Q_ASSERT(exposedWindow->winId() == engine->window()); // one thread+engine for each window engine->setWindowSize(wme->size, wme->dpr); if (Q_UNLIKELY(debug_loop())) qDebug() << "RT - WM_RequestSync" << exposedWindow; @@ -374,6 +392,7 @@ bool QSGD3D12RenderThread::event(QEvent *e) // However, our hands are tied by the existing, synchronous APIs of // QQuickWindow and such. QQuickWindowPrivate *wd = QQuickWindowPrivate::get(wme->window); + rc->ensureInitializedEmitted(); wd->syncSceneGraph(); wd->renderSceneGraph(wme->window->size()); *wme->image = engine->executeAndWaitReadbackRenderTarget(); @@ -508,6 +527,7 @@ void QSGD3D12RenderThread::sync(bool inExpose) if (wd->renderer) wd->renderer->clearChangedFlag(); + rc->ensureInitializedEmitted(); wd->syncSceneGraph(); if (!hadRenderer && wd->renderer) { diff --git a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp index ff996e5362..9c4043791f 100644 --- a/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp +++ b/tests/auto/quick/qquickwindow/tst_qquickwindow.cpp @@ -45,6 +45,7 @@ #include <private/qguiapplication_p.h> #include <QRunnable> #include <QOpenGLFunctions> +#include <QSGRendererInterface> struct TouchEventData { QEvent::Type type; @@ -392,6 +393,9 @@ void tst_qquickwindow::openglContextCreatedSignal() window.show(); QTest::qWaitForWindowExposed(&window); + if (window.rendererInterface()->graphicsAPI() != QSGRendererInterface::OpenGL) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + QVERIFY(spy.size() > 0); QVariant ctx = spy.at(0).at(0); @@ -439,11 +443,7 @@ void tst_qquickwindow::constantUpdatesOnWindow_data() window.setGeometry(100, 100, 300, 200); window.show(); QTest::qWaitForWindowExposed(&window); -#ifndef QT_NO_OPENGL - bool threaded = window.openglContext()->thread() != QGuiApplication::instance()->thread(); -#else - bool threaded = false; -#endif + const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); if (threaded) { QTest::newRow("blocked, beforeRender") << true << QByteArray(SIGNAL(beforeRendering())); QTest::newRow("blocked, afterRender") << true << QByteArray(SIGNAL(afterRendering())); @@ -1233,18 +1233,15 @@ void tst_qquickwindow::headless() QVERIFY(QTest::qWaitForWindowExposed(window)); QVERIFY(window->isVisible()); -#ifndef QT_NO_OPENGL - bool threaded = window->openglContext()->thread() != QThread::currentThread(); -#else - bool threaded = false; -#endif + const bool threaded = QQuickWindowPrivate::get(window)->context->thread() != QThread::currentThread(); QSignalSpy initialized(window, SIGNAL(sceneGraphInitialized())); QSignalSpy invalidated(window, SIGNAL(sceneGraphInvalidated())); -#ifndef QT_NO_OPENGL // Verify that the window is alive and kicking - QVERIFY(window->openglContext() != 0); -#endif + QVERIFY(window->isSceneGraphInitialized()); + + const bool isGL = window->rendererInterface()->graphicsAPI() == QSGRendererInterface::OpenGL; + // Store the visual result QImage originalContent = window->grabWindow(); @@ -1253,8 +1250,9 @@ void tst_qquickwindow::headless() window->releaseResources(); if (threaded) { - QTRY_COMPARE(invalidated.size(), 1); - QVERIFY(!window->openglContext()); + QTRY_VERIFY(invalidated.size() >= 1); + if (isGL) + QVERIFY(!window->isSceneGraphInitialized()); } #ifndef QT_NO_OPENGL if (QGuiApplication::platformName() == QLatin1String("windows") @@ -1272,9 +1270,8 @@ void tst_qquickwindow::headless() if (threaded) QTRY_COMPARE(initialized.size(), 1); -#ifndef QT_NO_OPENGL - QVERIFY(window->openglContext() != 0); -#endif + + QVERIFY(window->isSceneGraphInitialized()); // Verify that the visual output is the same QImage newContent = window->grabWindow(); @@ -1295,14 +1292,10 @@ void tst_qquickwindow::noUpdateWhenNothingChanges() // the initial expose with a second expose or more. Let these go // through before we let the test continue. QTest::qWait(100); -#ifndef QT_NO_OPENGL - if (window.openglContext()->thread() == QGuiApplication::instance()->thread()) { + if (QQuickWindowPrivate::get(&window)->context->thread() == QGuiApplication::instance()->thread()) { QSKIP("Only threaded renderloop implements this feature"); return; } -#else - return; -#endif QSignalSpy spy(&window, SIGNAL(frameSwapped())); rect.update(); @@ -1606,7 +1599,6 @@ void tst_qquickwindow::hideThenDelete() QSignalSpy *openglDestroyed = 0; QSignalSpy *sgInvalidated = 0; - bool threaded = false; { QQuickWindow window; @@ -1621,17 +1613,23 @@ void tst_qquickwindow::hideThenDelete() window.show(); QTest::qWaitForWindowExposed(&window); + const bool threaded = QQuickWindowPrivate::get(&window)->context->thread() != QGuiApplication::instance()->thread(); + const bool isGL = window.rendererInterface()->graphicsAPI() == QSGRendererInterface::OpenGL; #ifndef QT_NO_OPENGL - threaded = window.openglContext()->thread() != QThread::currentThread(); - openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); + if (isGL) + openglDestroyed = new QSignalSpy(window.openglContext(), SIGNAL(aboutToBeDestroyed())); #endif + sgInvalidated = new QSignalSpy(&window, SIGNAL(sceneGraphInvalidated())); window.hide(); QTRY_VERIFY(!window.isExposed()); -#ifndef QT_NO_OPENGL + if (threaded) { + if (!isGL) + QSKIP("Skipping persistency verification due to not running with OpenGL"); + if (!persistentSG) { QVERIFY(sgInvalidated->size() > 0); if (!persistentGL) @@ -1643,12 +1641,12 @@ void tst_qquickwindow::hideThenDelete() QCOMPARE(openglDestroyed->size(), 0); } } -#endif } QVERIFY(sgInvalidated->size() > 0); #ifndef QT_NO_OPENGL - QVERIFY(openglDestroyed->size() > 0); + if (openglDestroyed) + QVERIFY(openglDestroyed->size() > 0); #endif } @@ -2046,6 +2044,9 @@ void tst_qquickwindow::defaultSurfaceFormat() window.show(); QVERIFY(QTest::qWaitForWindowExposed(&window)); + if (window.rendererInterface()->graphicsAPI() != QSGRendererInterface::OpenGL) + QSKIP("Skipping OpenGL context test due to not running with OpenGL"); + const QSurfaceFormat reqFmt = window.requestedFormat(); QCOMPARE(format.swapInterval(), reqFmt.swapInterval()); QCOMPARE(format.redBufferSize(), reqFmt.redBufferSize()); @@ -2181,27 +2182,30 @@ void tst_qquickwindow::testRenderJob() QCOMPARE(completedJobs.size(), 1); #ifndef QT_NO_OPENGL - // Do a synchronized GL job. - GLubyte readPixel[4] = {0, 0, 0, 0}; - GlRenderJob *glJob = new GlRenderJob(readPixel); - if (window.openglContext()->thread() != QThread::currentThread()) { - QMutex mutex; - QWaitCondition condition; - glJob->mutex = &mutex; - glJob->condition = &condition; - mutex.lock(); - window.scheduleRenderJob(glJob, QQuickWindow::NoStage); - condition.wait(&mutex); - mutex.unlock(); - } else { - window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + if (window.rendererInterface()->graphicsAPI() == QSGRendererInterface::OpenGL) { + // Do a synchronized GL job. + GLubyte readPixel[4] = {0, 0, 0, 0}; + GlRenderJob *glJob = new GlRenderJob(readPixel); + if (window.openglContext()->thread() != QThread::currentThread()) { + QMutex mutex; + QWaitCondition condition; + glJob->mutex = &mutex; + glJob->condition = &condition; + mutex.lock(); + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + condition.wait(&mutex); + mutex.unlock(); + } else { + window.scheduleRenderJob(glJob, QQuickWindow::NoStage); + } + QCOMPARE(int(readPixel[0]), 255); + QCOMPARE(int(readPixel[1]), 0); + QCOMPARE(int(readPixel[2]), 0); + QCOMPARE(int(readPixel[3]), 255); } - QCOMPARE(int(readPixel[0]), 255); - QCOMPARE(int(readPixel[1]), 0); - QCOMPARE(int(readPixel[2]), 0); - QCOMPARE(int(readPixel[3]), 255); -#endif } +#endif + // Verify that jobs are deleted when window is not rendered at all completedJobs.clear(); RenderJob::deleted = 0; |