aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-05-07 15:33:47 +0200
committerLaszlo Agocs <laszlo.agocs@theqtcompany.com>2016-05-08 20:03:24 +0000
commit3fe2ecccc96ef1d8243e0683853c5db8c6ed9ee0 (patch)
tree8a71bdc03443808cbb6fa4cc27ac34f8e9fd861c
parente3716cdf88a09109e368adc4f73fc52ff6325f83 (diff)
D3D12: Massage tst_qquickwindow and some sg semantics
Change-Id: Ic4cc9ae5c1df2ab7e1da50ac414dc3d7f264e691 Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp9
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h4
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp24
-rw-r--r--tests/auto/quick/qquickwindow/tst_qquickwindow.cpp100
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;