aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp')
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp536
1 files changed, 0 insertions, 536 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
deleted file mode 100644
index 0d501f48c0..0000000000
--- a/src/plugins/scenegraph/d3d12/qsgd3d12renderloop.cpp
+++ /dev/null
@@ -1,536 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtQuick module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qsgd3d12renderloop_p.h"
-#include "qsgd3d12engine_p.h"
-#include "qsgd3d12context_p.h"
-#include "qsgd3d12rendercontext_p.h"
-#include "qsgd3d12shadereffectnode_p.h"
-#include <private/qquickwindow_p.h>
-#include <private/qquickprofiler_p.h>
-#include <private/qquickanimatorcontroller_p.h>
-#include <QElapsedTimer>
-#include <QGuiApplication>
-#include <QScreen>
-
-QT_BEGIN_NAMESPACE
-
-// NOTE: Avoid categorized logging. It is slow.
-
-#define DECLARE_DEBUG_VAR(variable) \
- static bool debug_ ## variable() \
- { static bool value = qgetenv("QSG_RENDERER_DEBUG").contains(QT_STRINGIFY(variable)); return value; }
-
-DECLARE_DEBUG_VAR(loop)
-DECLARE_DEBUG_VAR(time)
-
-
-// This render loop operates on the gui (main) thread.
-// Conceptually it matches the OpenGL 'windows' render loop.
-
-static inline int qsgrl_animation_interval()
-{
- const qreal refreshRate = QGuiApplication::primaryScreen() ? QGuiApplication::primaryScreen()->refreshRate() : 0;
- return refreshRate < 1 ? 16 : int(1000 / refreshRate);
-}
-
-QSGD3D12RenderLoop::QSGD3D12RenderLoop()
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug("new d3d12 render loop");
-
- sg = new QSGD3D12Context;
-
- m_anims = sg->createAnimationDriver(this);
- connect(m_anims, &QAnimationDriver::started, this, &QSGD3D12RenderLoop::onAnimationStarted);
- connect(m_anims, &QAnimationDriver::stopped, this, &QSGD3D12RenderLoop::onAnimationStopped);
- m_anims->install();
-
- m_vsyncDelta = qsgrl_animation_interval();
-}
-
-QSGD3D12RenderLoop::~QSGD3D12RenderLoop()
-{
- delete sg;
-}
-
-void QSGD3D12RenderLoop::show(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "show" << window;
-}
-
-void QSGD3D12RenderLoop::hide(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "hide" << window;
-}
-
-void QSGD3D12RenderLoop::resize(QQuickWindow *window)
-{
- if (!m_windows.contains(window) || window->size().isEmpty())
- return;
-
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "resize" << window;
-
- const WindowData &data(m_windows[window]);
-
- if (!data.exposed)
- return;
-
- if (data.engine)
- data.engine->setWindowSize(window->size(), window->effectiveDevicePixelRatio());
-}
-
-void QSGD3D12RenderLoop::windowDestroyed(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "window destroyed" << window;
-
- if (!m_windows.contains(window))
- return;
-
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
- wd->fireAboutToStop();
-
- WindowData &data(m_windows[window]);
- QSGD3D12Engine *engine = data.engine;
- QSGD3D12RenderContext *rc = data.rc;
- m_windows.remove(window);
-
- // QSGNode destruction may release graphics resources in use so wait first.
- engine->waitGPU();
-
- // Bye bye nodes...
- wd->cleanupNodesOnShutdown();
-
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
-
- rc->invalidate();
-
- delete rc;
- delete engine;
-
- delete wd->animationController;
-}
-
-void QSGD3D12RenderLoop::exposeWindow(QQuickWindow *window)
-{
- WindowData data;
- data.exposed = true;
- data.engine = new QSGD3D12Engine;
- data.rc = static_cast<QSGD3D12RenderContext *>(QQuickWindowPrivate::get(window)->context);
- data.rc->setEngine(data.engine);
- m_windows[window] = data;
-
- const int samples = window->format().samples();
- const bool alpha = window->format().alphaBufferSize() > 0;
- const qreal dpr = window->effectiveDevicePixelRatio();
-
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "initializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
-
- data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
-}
-
-void QSGD3D12RenderLoop::obscureWindow(QQuickWindow *window)
-{
- m_windows[window].exposed = false;
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
- wd->fireAboutToStop();
-}
-
-void QSGD3D12RenderLoop::exposureChanged(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "exposure changed" << window << window->isExposed();
-
- if (window->isExposed()) {
- if (!m_windows.contains(window))
- exposeWindow(window);
-
- // Stop non-visual animation timer as we now have a window rendering.
- if (m_animationTimer && somethingVisible()) {
- killTimer(m_animationTimer);
- m_animationTimer = 0;
- }
- // If we have a pending timer and we get an expose, we need to stop it.
- // Otherwise we get two frames and two animation ticks in the same time interval.
- if (m_updateTimer) {
- killTimer(m_updateTimer);
- m_updateTimer = 0;
- }
-
- WindowData &data(m_windows[window]);
- data.exposed = true;
- data.updatePending = true;
-
- render();
-
- } else if (m_windows.contains(window)) {
- obscureWindow(window);
-
- // Potentially start the non-visual animation timer if nobody is rendering.
- if (m_anims->isRunning() && !somethingVisible() && !m_animationTimer)
- m_animationTimer = startTimer(m_vsyncDelta);
- }
-}
-
-QImage QSGD3D12RenderLoop::grab(QQuickWindow *window)
-{
- const bool tempExpose = !m_windows.contains(window);
- if (tempExpose)
- exposeWindow(window);
-
- m_windows[window].grabOnly = true;
-
- renderWindow(window);
-
- QImage grabbed = m_grabContent;
- m_grabContent = QImage();
-
- if (tempExpose)
- obscureWindow(window);
-
- return grabbed;
-}
-
-bool QSGD3D12RenderLoop::somethingVisible() const
-{
- for (auto it = m_windows.constBegin(), itEnd = m_windows.constEnd(); it != itEnd; ++it) {
- if (it.key()->isVisible() && it.key()->isExposed())
- return true;
- }
- return false;
-}
-
-void QSGD3D12RenderLoop::maybePostUpdateTimer()
-{
- if (!m_updateTimer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("starting update timer");
- m_updateTimer = startTimer(m_vsyncDelta / 3);
- }
-}
-
-void QSGD3D12RenderLoop::update(QQuickWindow *window)
-{
- maybeUpdate(window);
-}
-
-void QSGD3D12RenderLoop::maybeUpdate(QQuickWindow *window)
-{
- if (!m_windows.contains(window) || !somethingVisible())
- return;
-
- m_windows[window].updatePending = true;
- maybePostUpdateTimer();
-}
-
-QAnimationDriver *QSGD3D12RenderLoop::animationDriver() const
-{
- return m_anims;
-}
-
-QSGContext *QSGD3D12RenderLoop::sceneGraphContext() const
-{
- return sg;
-}
-
-QSGRenderContext *QSGD3D12RenderLoop::createRenderContext(QSGContext *) const
-{
- // The rendercontext and engine are per-window, like with the threaded
- // loop, but unlike the non-threaded OpenGL variants.
- return sg->createRenderContext();
-}
-
-void QSGD3D12RenderLoop::releaseResources(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "releaseResources" << window;
-}
-
-void QSGD3D12RenderLoop::postJob(QQuickWindow *window, QRunnable *job)
-{
- Q_UNUSED(window);
- Q_ASSERT(job);
- Q_ASSERT(window);
- job->run();
- delete job;
-}
-
-QSurface::SurfaceType QSGD3D12RenderLoop::windowSurfaceType() const
-{
- return QSurface::OpenGLSurface;
-}
-
-bool QSGD3D12RenderLoop::interleaveIncubation() const
-{
- return m_anims->isRunning() && somethingVisible();
-}
-
-void QSGD3D12RenderLoop::onAnimationStarted()
-{
- if (!somethingVisible()) {
- if (!m_animationTimer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("starting non-visual animation timer");
- m_animationTimer = startTimer(m_vsyncDelta);
- }
- } else {
- maybePostUpdateTimer();
- }
-}
-
-void QSGD3D12RenderLoop::onAnimationStopped()
-{
- if (m_animationTimer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("stopping non-visual animation timer");
- killTimer(m_animationTimer);
- m_animationTimer = 0;
- }
-}
-
-bool QSGD3D12RenderLoop::event(QEvent *event)
-{
- switch (event->type()) {
- case QEvent::Timer:
- {
- QTimerEvent *te = static_cast<QTimerEvent *>(event);
- if (te->timerId() == m_animationTimer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("animation tick while no windows exposed");
- m_anims->advance();
- } else if (te->timerId() == m_updateTimer) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("update timeout - rendering");
- killTimer(m_updateTimer);
- m_updateTimer = 0;
- render();
- }
- return true;
- }
- default:
- break;
- }
-
- return QObject::event(event);
-}
-
-void QSGD3D12RenderLoop::render()
-{
- bool rendered = false;
- for (auto it = m_windows.begin(), itEnd = m_windows.end(); it != itEnd; ++it) {
- if (it->updatePending) {
- it->updatePending = false;
- renderWindow(it.key());
- rendered = true;
- }
- }
-
- if (!rendered) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("render - no changes, sleep");
- QThread::msleep(m_vsyncDelta);
- }
-
- if (m_anims->isRunning()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("render - advancing animations");
-
- m_anims->advance();
-
- // It is not given that animations triggered another maybeUpdate()
- // and thus another render pass, so to keep things running,
- // make sure there is another frame pending.
- maybePostUpdateTimer();
-
- emit timeToIncubate();
- }
-}
-
-void QSGD3D12RenderLoop::renderWindow(QQuickWindow *window)
-{
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "renderWindow" << window;
-
- QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window);
- if (!m_windows.contains(window) || !window->geometry().isValid())
- return;
-
- WindowData &data(m_windows[window]);
- if (!data.exposed) { // not the same as window->isExposed(), when grabbing invisible windows for instance
- if (Q_UNLIKELY(debug_loop()))
- qDebug("renderWindow - not exposed, abort");
- return;
- }
-
- if (!data.grabOnly)
- wd->flushFrameSynchronousEvents();
-
- QElapsedTimer renderTimer;
- qint64 renderTime = 0, syncTime = 0, polishTime = 0;
- const bool profileFrames = debug_time();
- if (profileFrames)
- renderTimer.start();
- Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
-
- wd->polishItems();
-
- if (profileFrames)
- polishTime = renderTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
- QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphPolishPolish);
-
- emit window->afterAnimating();
-
- // The native window may change in some (quite artificial) cases, e.g. due
- // to a hide - destroy - show on the QWindow.
- bool needsWindow = !data.engine->window();
- if (data.engine->window() && data.engine->window() != window->winId()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("sync - native window handle changes for active engine");
- data.engine->waitGPU();
- wd->cleanupNodesOnShutdown();
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- data.rc->invalidate();
- data.engine->releaseResources();
- needsWindow = true;
- }
- if (needsWindow) {
- // Must only ever get here when there is no window or releaseResources() has been called.
- const int samples = window->format().samples();
- const bool alpha = window->format().alphaBufferSize() > 0;
- const qreal dpr = window->effectiveDevicePixelRatio();
- if (Q_UNLIKELY(debug_loop()))
- qDebug() << "sync - reinitializing D3D12 engine" << window << window->size() << dpr << samples << alpha;
- data.engine->attachToWindow(window->winId(), window->size(), dpr, samples, alpha);
- }
-
- // Recover from device loss.
- if (!data.engine->hasResources()) {
- if (Q_UNLIKELY(debug_loop()))
- qDebug("sync - device was lost, resetting scenegraph");
- wd->cleanupNodesOnShutdown();
- QSGD3D12ShaderEffectNode::cleanupMaterialTypeCache();
- data.rc->invalidate();
- }
-
- data.rc->initialize(nullptr);
-
- wd->syncSceneGraph();
- data.rc->endSync();
-
- if (profileFrames)
- syncTime = renderTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphRenderLoopSync);
-
- wd->renderSceneGraph(window->size());
-
- if (profileFrames)
- renderTime = renderTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphRenderLoopRender);
-
- if (!data.grabOnly) {
- // The engine is able to have multiple frames in flight. This in effect is
- // similar to BufferQueueingOpenGL. Provide an env var to force the
- // traditional blocking swap behavior, just in case.
- static bool blockOnEachFrame = qEnvironmentVariableIntValue("QT_D3D_BLOCKING_PRESENT") != 0;
-
- if (window->isVisible()) {
- data.engine->present();
- if (blockOnEachFrame)
- data.engine->waitGPU();
- // The concept of "frame swaps" is quite misleading by default, when
- // blockOnEachFrame is not used, but emit it for compatibility.
- wd->fireFrameSwapped();
- } else {
- if (blockOnEachFrame)
- data.engine->waitGPU();
- }
- } else {
- m_grabContent = data.engine->executeAndWaitReadbackRenderTarget();
- data.grabOnly = false;
- }
-
- qint64 swapTime = 0;
- if (profileFrames)
- swapTime = renderTimer.nsecsElapsed();
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphRenderLoopSwap);
-
- if (Q_UNLIKELY(debug_time())) {
- static QTime lastFrameTime = QTime::currentTime();
- qDebug("Frame rendered with 'd3d12' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
- int(swapTime / 1000000),
- int(polishTime / 1000000),
- int((syncTime - polishTime) / 1000000),
- int((renderTime - syncTime) / 1000000),
- int((swapTime - renderTime) / 10000000),
- int(lastFrameTime.msecsTo(QTime::currentTime())));
- lastFrameTime = QTime::currentTime();
- }
-
- // Simulate device loss if requested.
- static int devLossTest = qEnvironmentVariableIntValue("QT_D3D_TEST_DEVICE_LOSS");
- if (devLossTest > 0) {
- static QElapsedTimer kt;
- static bool timerRunning = false;
- if (!timerRunning) {
- kt.start();
- timerRunning = true;
- } else if (kt.elapsed() > 5000) {
- --devLossTest;
- kt.restart();
- data.engine->simulateDeviceLoss();
- }
- }
-}
-
-int QSGD3D12RenderLoop::flags() const
-{
- return SupportsGrabWithoutExpose;
-}
-
-QT_END_NAMESPACE