1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "qquickwindowmanager_p.h"
43 #include "qquickthreadedwindowmanager_p.h"
45 #include <QtCore/QCoreApplication>
46 #include <QtCore/QTime>
47 #include <QtCore/private/qabstractanimation_p.h>
49 #include <QtGui/QOpenGLContext>
50 #include <QtGui/private/qguiapplication_p.h>
51 #include <qpa/qplatformintegration.h>
53 #include <QtQml/private/qqmlglobal_p.h>
55 #include <QtQuick/QQuickWindow>
56 #include <QtQuick/private/qquickwindow_p.h>
57 #include <QtQuick/private/qsgcontext_p.h>
61 extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
64 expectations for this manager to work:
65 - one opengl context to render multiple windows
66 - OpenGL pipeline will not block for vsync in swap
67 - OpenGL pipeline will block based on a full buffer queue.
68 - Multiple screens can share the OpenGL context
69 - Animations are advanced for all windows once per swap
72 DEFINE_BOOL_CONFIG_OPTION(qmlNoThreadedRenderer, QML_BAD_GUI_RENDER_LOOP);
73 DEFINE_BOOL_CONFIG_OPTION(qmlForceThreadedRenderer, QML_FORCE_THREADED_RENDERER); // Might trigger graphics driver threading bugs, use at own risk
75 QQuickWindowManager::~QQuickWindowManager()
79 class QQuickTrivialWindowManager : public QObject, public QQuickWindowManager
83 QQuickTrivialWindowManager();
85 void show(QQuickWindow *window);
86 void hide(QQuickWindow *window);
88 void windowDestroyed(QQuickWindow *window);
91 void renderWindow(QQuickWindow *window);
92 void exposureChanged(QQuickWindow *window);
93 QImage grab(QQuickWindow *window);
94 void resize(QQuickWindow *window, const QSize &size);
97 void maybeUpdate(QQuickWindow *window);
98 void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation.
100 void releaseResources() { }
102 volatile bool *allowMainThreadProcessing();
104 QSGContext *sceneGraphContext() const;
106 bool event(QEvent *);
109 bool updatePending : 1;
113 QHash<QQuickWindow *, WindowData> m_windows;
124 QQuickWindowManager *QQuickWindowManager::instance()
126 static QQuickWindowManager *theInstance;
130 theInstance = QSGContext::createWindowManager();
132 bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
133 bool fancy = bufferQueuing
134 && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL);
135 if (qmlNoThreadedRenderer())
137 else if (qmlForceThreadedRenderer())
140 // Enable fixed animation steps...
141 QByteArray fixed = qgetenv("QML_FIXED_ANIMATION_STEP");
142 bool fixedAnimationSteps = bufferQueuing;
144 fixedAnimationSteps = false;
145 else if (fixed.length())
146 fixedAnimationSteps = true;
147 if (fixedAnimationSteps)
148 QUnifiedTimer::instance(true)->setConsistentTiming(true);
152 ? (QQuickWindowManager*) new QQuickRenderThreadSingleContextWindowManager
153 : (QQuickWindowManager*) new QQuickTrivialWindowManager;
159 QQuickTrivialWindowManager::QQuickTrivialWindowManager()
161 , eventPending(false)
163 sg = QSGContext::createDefaultContext();
167 void QQuickTrivialWindowManager::show(QQuickWindow *window)
170 data.updatePending = false;
171 data.grabOnly = false;
172 m_windows[window] = data;
177 void QQuickTrivialWindowManager::hide(QQuickWindow *window)
179 if (!m_windows.contains(window))
182 m_windows.remove(window);
183 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
184 cd->cleanupNodesOnShutdown();
186 if (m_windows.size() == 0) {
193 void QQuickTrivialWindowManager::windowDestroyed(QQuickWindow *window)
198 void QQuickTrivialWindowManager::renderWindow(QQuickWindow *window)
200 if (!window->isExposed() || !m_windows.contains(window))
203 WindowData &data = const_cast<WindowData &>(m_windows[window]);
205 QQuickWindow *masterWindow = 0;
206 if (!window->isVisible()) {
207 // Find a "proper surface" to bind...
208 for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
209 it != m_windows.constEnd() && !masterWindow; ++it) {
210 if (it.key()->isVisible())
211 masterWindow = it.key();
214 masterWindow = window;
221 gl = new QOpenGLContext();
222 gl->setFormat(masterWindow->requestedFormat());
224 if (!gl->makeCurrent(masterWindow))
225 qWarning("QQuickWindow: makeCurrent() failed...");
228 gl->makeCurrent(masterWindow);
231 bool alsoSwap = data.updatePending;
232 data.updatePending = false;
234 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
236 cd->syncSceneGraph();
237 cd->renderSceneGraph(window->size());
240 grabContent = qt_gl_read_framebuffer(window->size(), false, false);
241 data.grabOnly = false;
244 if (alsoSwap && window->isVisible()) {
245 gl->swapBuffers(window);
246 cd->fireFrameSwapped();
249 // Might have been set during syncSceneGraph()
250 if (data.updatePending)
254 void QQuickTrivialWindowManager::exposureChanged(QQuickWindow *window)
256 if (window->isExposed())
260 QImage QQuickTrivialWindowManager::grab(QQuickWindow *window)
262 if (!m_windows.contains(window))
265 m_windows[window].grabOnly = true;
267 renderWindow(window);
269 QImage grabbed = grabContent;
270 grabContent = QImage();
276 void QQuickTrivialWindowManager::resize(QQuickWindow *, const QSize &)
282 void QQuickTrivialWindowManager::maybeUpdate(QQuickWindow *window)
284 if (!m_windows.contains(window))
287 m_windows[window].updatePending = true;
290 QCoreApplication::postEvent(this, new QEvent(QEvent::User));
295 void QQuickTrivialWindowManager::wakeup()
299 volatile bool *QQuickTrivialWindowManager::allowMainThreadProcessing()
306 QSGContext *QQuickTrivialWindowManager::sceneGraphContext() const
312 bool QQuickTrivialWindowManager::event(QEvent *e)
314 if (e->type() == QEvent::User) {
315 eventPending = false;
316 for (QHash<QQuickWindow *, WindowData>::const_iterator it = m_windows.constBegin();
317 it != m_windows.constEnd(); ++it) {
318 const WindowData &data = it.value();
319 if (data.updatePending)
320 renderWindow(it.key());
324 return QObject::event(e);
327 #include "qquickwindowmanager.moc"