aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgwindowsrenderloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgwindowsrenderloop.cpp')
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp552
1 files changed, 0 insertions, 552 deletions
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
deleted file mode 100644
index 03c9183126..0000000000
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ /dev/null
@@ -1,552 +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 "qsgwindowsrenderloop_p.h"
-#include <QtCore/QCoreApplication>
-#include <QtCore/QLibraryInfo>
-#include <QtCore/QThread>
-
-#include <QtGui/QScreen>
-#include <QtGui/QGuiApplication>
-#include <QtGui/QOffscreenSurface>
-
-#include <QtQuick/private/qsgcontext_p.h>
-#include <QtQuick/private/qquickwindow_p.h>
-#include <QtQuick/private/qquickitem_p.h>
-#include <QtQuick/private/qsgrenderer_p.h>
-#include <QtQuick/private/qsgdefaultrendercontext_p.h>
-
-#include <QtQuick/QQuickWindow>
-
-#include <private/qquickprofiler_p.h>
-#include <private/qquickanimatorcontroller_p.h>
-
-#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
-#include <private/qquickopenglshadereffectnode_p.h>
-#endif
-
-#include <qtquick_tracepoints_p.h>
-
-QT_BEGIN_NAMESPACE
-
-// Single-threaded render loop with a custom animation driver. Like a
-// combination of basic+threaded but still working on the main thread. Only
-// compatible with direct OpenGL, no RHI support here.
-
-extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
-
-#define RLDEBUG(x) qCDebug(QSG_LOG_RENDERLOOP, x)
-
-static QElapsedTimer qsg_render_timer;
-#define QSG_LOG_TIME_SAMPLE(sampleName) \
- qint64 sampleName = 0; \
- if (QSG_LOG_TIME_RENDERLOOP().isDebugEnabled()) \
- sampleName = qsg_render_timer.nsecsElapsed(); \
-
-#define QSG_RENDER_TIMING_SAMPLE(frameType, sampleName, position) \
- QSG_LOG_TIME_SAMPLE(sampleName) \
- Q_QUICK_SG_PROFILE_RECORD(frameType, position);
-
-
-QSGWindowsRenderLoop::QSGWindowsRenderLoop()
- : m_gl(nullptr)
- , m_sg(QSGContext::createDefaultContext())
- , m_updateTimer(0)
- , m_animationTimer(0)
-{
- m_rc = static_cast<QSGDefaultRenderContext *>(m_sg->createRenderContext());
-
- m_vsyncDelta = 1000 / QGuiApplication::primaryScreen()->refreshRate();
- if (m_vsyncDelta <= 0)
- m_vsyncDelta = 16;
-
- RLDEBUG("Windows Render Loop created");
-
- m_animationDriver = m_sg->createAnimationDriver(m_sg);
- connect(m_animationDriver, SIGNAL(started()), this, SLOT(started()));
- connect(m_animationDriver, SIGNAL(stopped()), this, SLOT(stopped()));
- m_animationDriver->install();
-
- qsg_render_timer.start();
-}
-
-QSGWindowsRenderLoop::~QSGWindowsRenderLoop()
-{
- delete m_rc;
- delete m_sg;
-}
-
-bool QSGWindowsRenderLoop::interleaveIncubation() const
-{
- return m_animationDriver->isRunning() && anyoneShowing();
-}
-
-QSGWindowsRenderLoop::WindowData *QSGWindowsRenderLoop::windowData(QQuickWindow *window)
-{
- for (int i=0; i<m_windows.size(); ++i) {
- WindowData &wd = m_windows[i];
- if (wd.window == window)
- return &wd;
- }
- return nullptr;
-}
-
-void QSGWindowsRenderLoop::maybePostUpdateTimer()
-{
- if (!m_updateTimer) {
- RLDEBUG(" - posting event");
- m_updateTimer = startTimer(m_vsyncDelta / 3);
- }
-}
-
-/*
- * If no windows are showing, start ticking animations using a timer,
- * otherwise, start rendering
- */
-void QSGWindowsRenderLoop::started()
-{
- RLDEBUG("Animations started...");
- if (!anyoneShowing()) {
- if (m_animationTimer == 0) {
- RLDEBUG(" - starting non-visual animation timer");
- m_animationTimer = startTimer(m_vsyncDelta);
- }
- } else {
- maybePostUpdateTimer();
- }
-}
-
-void QSGWindowsRenderLoop::stopped()
-{
- RLDEBUG("Animations stopped...");
- if (m_animationTimer) {
- RLDEBUG(" - stopping non-visual animation timer");
- killTimer(m_animationTimer);
- m_animationTimer = 0;
- }
-}
-
-void QSGWindowsRenderLoop::show(QQuickWindow *window)
-{
- RLDEBUG("show");
- if (windowData(window) != nullptr)
- return;
-
- // This happens before the platform window is shown, but after
- // it is created. Creating the GL context takes a lot of time
- // (hundreds of milliseconds) and will prevent us from rendering
- // the first frame in time for the initial show on screen.
- // By preparing the GL context here, it is feasible (if the app
- // is quick enough) to have a perfect first frame.
- if (!m_gl) {
- RLDEBUG(" - creating GL context");
- m_gl = new QOpenGLContext();
- m_gl->setFormat(window->requestedFormat());
- m_gl->setScreen(window->screen());
- if (qt_gl_global_share_context())
- m_gl->setShareContext(qt_gl_global_share_context());
- bool created = m_gl->create();
- if (!created) {
- delete m_gl;
- m_gl = nullptr;
- handleContextCreationFailure(window);
- return;
- }
-
- QQuickWindowPrivate::get(window)->fireOpenGLContextCreated(m_gl);
-
- RLDEBUG(" - making current");
- bool current = m_gl->makeCurrent(window);
- RLDEBUG(" - initializing SG");
- if (current) {
- QSGDefaultRenderContext::InitParams rcParams;
- rcParams.sampleCount = qMax(1, m_gl->format().samples());
- rcParams.openGLContext = m_gl;
- rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
- rcParams.maybeSurface = window;
- m_rc->initialize(&rcParams);
- }
- }
-
- WindowData data;
- data.window = window;
- data.pendingUpdate = false;
- m_windows << data;
-
- RLDEBUG(" - done with show");
-}
-
-void QSGWindowsRenderLoop::hide(QQuickWindow *window)
-{
- RLDEBUG("hide");
- // The expose event is queued while hide is sent synchronously, so
- // the value might not be updated yet. (plus that the windows plugin
- // sends exposed=true when it goes to hidden, so it is doubly broken)
- // The check is made here, after the removal from m_windows, so
- // anyoneShowing will report the right value.
- if (window->isExposed())
- handleObscurity();
- if (!m_gl)
- return;
- QQuickWindowPrivate::get(window)->fireAboutToStop();
-}
-
-void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
-{
- RLDEBUG("windowDestroyed");
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == window) {
- m_windows.removeAt(i);
- break;
- }
- }
-
- hide(window);
-
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
-
- bool current = false;
- QScopedPointer<QOffscreenSurface> offscreenSurface;
- if (m_gl) {
- QSurface *surface = window;
- // There may be no platform window if the window got closed.
- if (!window->handle()) {
- offscreenSurface.reset(new QOffscreenSurface);
- offscreenSurface->setFormat(m_gl->format());
- offscreenSurface->create();
- surface = offscreenSurface.data();
- }
- current = m_gl->makeCurrent(surface);
- }
- if (Q_UNLIKELY(!current))
- RLDEBUG("cleanup without an OpenGL context");
-
-#if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl)
- if (current)
- QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache();
-#endif
-
- d->cleanupNodesOnShutdown();
- if (m_windows.size() == 0) {
- d->context->invalidate();
- delete m_gl;
- m_gl = nullptr;
- } else if (m_gl && current) {
- m_gl->doneCurrent();
- }
-
- d->animationController.reset();
-}
-
-bool QSGWindowsRenderLoop::anyoneShowing() const
-{
- for (const WindowData &wd : qAsConst(m_windows))
- if (wd.window->isVisible() && wd.window->isExposed() && wd.window->size().isValid())
- return true;
- return false;
-}
-
-void QSGWindowsRenderLoop::exposureChanged(QQuickWindow *window)
-{
-
- if (windowData(window) == nullptr)
- return;
-
- if (window->isExposed() && window->isVisible()) {
-
- // Stop non-visual animation timer as we now have a window rendering
- if (m_animationTimer && anyoneShowing()) {
- RLDEBUG(" - stopping non-visual animation timer");
- killTimer(m_animationTimer);
- m_animationTimer = 0;
- }
-
- RLDEBUG("exposureChanged - exposed");
- WindowData *wd = windowData(window);
- wd->pendingUpdate = true;
-
- // 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) {
- RLDEBUG(" - killing pending update timer");
- killTimer(m_updateTimer);
- m_updateTimer = 0;
- }
- render();
- } else {
- handleObscurity();
- }
-}
-
-void QSGWindowsRenderLoop::handleObscurity()
-{
- RLDEBUG("handleObscurity");
- // Potentially start the non-visual animation timer if nobody is rendering
- if (m_animationDriver->isRunning() && !anyoneShowing() && !m_animationTimer) {
- RLDEBUG(" - starting non-visual animation timer");
- m_animationTimer = startTimer(m_vsyncDelta);
- }
-}
-
-QImage QSGWindowsRenderLoop::grab(QQuickWindow *window)
-{
- RLDEBUG("grab");
- if (!m_gl)
- return QImage();
-
- m_gl->makeCurrent(window);
-
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
- d->polishItems();
- d->syncSceneGraph();
- d->renderSceneGraph(window->size());
-
- bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() != 255;
- QImage image = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
- image.setDevicePixelRatio(window->effectiveDevicePixelRatio());
- return image;
-}
-
-void QSGWindowsRenderLoop::update(QQuickWindow *window)
-{
- RLDEBUG("update");
- maybeUpdate(window);
-}
-
-void QSGWindowsRenderLoop::maybeUpdate(QQuickWindow *window)
-{
- RLDEBUG("maybeUpdate");
-
- WindowData *wd = windowData(window);
- if (!wd || !anyoneShowing())
- return;
-
- wd->pendingUpdate = true;
- maybePostUpdateTimer();
-}
-
-QSGRenderContext *QSGWindowsRenderLoop::createRenderContext(QSGContext *) const
-{
- return m_rc;
-}
-
-bool QSGWindowsRenderLoop::event(QEvent *event)
-{
- switch (event->type()) {
- case QEvent::Timer: {
- QTimerEvent *te = static_cast<QTimerEvent *>(event);
- if (te->timerId() == m_animationTimer) {
- RLDEBUG("event : animation tick while nothing is showing");
- m_animationDriver->advance();
- } else if (te->timerId() == m_updateTimer) {
- RLDEBUG("event : update");
- killTimer(m_updateTimer);
- m_updateTimer = 0;
- render();
- }
- return true; }
- default:
- break;
- }
-
- return QObject::event(event);
-}
-
-/*
- * Go through all windows we control and render them in turn.
- * Then tick animations if active.
- */
-void QSGWindowsRenderLoop::render()
-{
- RLDEBUG("render");
- Q_TRACE(QSG_render_entry);
- bool rendered = false;
- for (const WindowData &wd : qAsConst(m_windows)) {
- if (wd.pendingUpdate) {
- const_cast<WindowData &>(wd).pendingUpdate = false;
- renderWindow(wd.window);
- rendered = true;
- }
- }
-
- if (!rendered) {
- RLDEBUG("no changes, sleep");
- QThread::msleep(m_vsyncDelta);
- }
-
- Q_TRACE(QSG_render_exit);
-
- if (m_animationDriver->isRunning()) {
- RLDEBUG("advancing animations");
- QSG_LOG_TIME_SAMPLE(time_start);
- Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphWindowsAnimations);
- Q_TRACE(QSG_animations_entry);
- m_animationDriver->advance();
- RLDEBUG("animations advanced");
-
- qCDebug(QSG_LOG_TIME_RENDERLOOP,
- "animations ticked in %dms",
- int((qsg_render_timer.nsecsElapsed() - time_start)/1000000));
-
- Q_TRACE(QSG_animations_exit);
- Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphWindowsAnimations, 1);
-
- // 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();
- }
-}
-
-/*
- * Render the contents of this window. First polish, then sync, render
- * then finally swap.
- *
- * Note: This render function does not implement aborting
- * the render call when sync step results in no scene graph changes,
- * like the threaded renderer does.
- */
-void QSGWindowsRenderLoop::renderWindow(QQuickWindow *window)
-{
- RLDEBUG("renderWindow");
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
-
- if (!d->isRenderable())
- return;
-
- if (!m_gl->makeCurrent(window)) {
- // Check for context loss.
- if (!m_gl->isValid()) {
- d->cleanupNodesOnShutdown();
- m_rc->invalidate();
- if (m_gl->create() && m_gl->makeCurrent(window)) {
- QSGDefaultRenderContext::InitParams rcParams;
- rcParams.sampleCount = qMax(1, m_gl->format().samples());
- rcParams.openGLContext = m_gl;
- rcParams.initialSurfacePixelSize = window->size() * window->effectiveDevicePixelRatio();
- rcParams.maybeSurface = window;
- m_rc->initialize(&rcParams);
- } else {
- return;
- }
- }
- }
-
- bool lastDirtyWindow = true;
- for (int i=0; i<m_windows.size(); ++i) {
- if ( m_windows[i].pendingUpdate) {
- lastDirtyWindow = false;
- break;
- }
- }
-
- d->flushFrameSynchronousEvents();
- // Event delivery or processing has caused the window to stop rendering.
- if (!windowData(window))
- return;
-
- Q_TRACE_SCOPE(QSG_renderWindow);
-
- QSG_LOG_TIME_SAMPLE(time_start);
- Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
- Q_TRACE(QSG_polishItems_entry);
-
- RLDEBUG(" - polishing");
- d->polishItems();
- QSG_LOG_TIME_SAMPLE(time_polished);
- Q_TRACE(QSG_polishItems_exit);
- Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
- QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphPolishPolish);
- Q_TRACE(QSG_sync_entry);
-
- emit window->afterAnimating();
-
- RLDEBUG(" - syncing");
- d->syncSceneGraph();
- if (lastDirtyWindow)
- m_rc->endSync();
- Q_TRACE(QSG_sync_exit);
- QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_synced,
- QQuickProfiler::SceneGraphRenderLoopSync);
- Q_TRACE(QSG_render_entry);
-
- RLDEBUG(" - rendering");
- d->renderSceneGraph(window->size());
- Q_TRACE(QSG_render_exit);
- QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_rendered,
- QQuickProfiler::SceneGraphRenderLoopRender);
- Q_TRACE(QSG_swap_entry);
-
- RLDEBUG(" - swapping");
- if (!d->customRenderStage || !d->customRenderStage->swap())
- m_gl->swapBuffers(window);
- Q_TRACE(QSG_swap_exit);
- QSG_RENDER_TIMING_SAMPLE(QQuickProfiler::SceneGraphRenderLoopFrame, time_swapped,
- QQuickProfiler::SceneGraphRenderLoopSwap);
-
- RLDEBUG(" - frameDone");
- d->fireFrameSwapped();
-
- qCDebug(QSG_LOG_TIME_RENDERLOOP()).nospace()
- << "Frame rendered with 'windows' renderloop in: " << (time_swapped - time_start) / 1000000 << "ms"
- << ", polish=" << (time_polished - time_start) / 1000000
- << ", sync=" << (time_synced - time_polished) / 1000000
- << ", render=" << (time_rendered - time_synced) / 1000000
- << ", swap=" << (time_swapped - time_rendered) / 1000000
- << " - " << window;
-
- Q_QUICK_SG_PROFILE_REPORT(QQuickProfiler::SceneGraphRenderLoopFrame,
- QQuickProfiler::SceneGraphRenderLoopSwap);
-}
-
-void QSGWindowsRenderLoop::releaseResources(QQuickWindow *w)
-{
- // No full invalidation of the rendercontext, just clear some caches.
- RLDEBUG("releaseResources");
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w);
- if (d->renderer)
- d->renderer->releaseCachedResources();
-}
-
-QT_END_NAMESPACE
-
-#include "moc_qsgwindowsrenderloop_p.cpp"