Update to 5.0.0-beta1
[profile/ivi/qtdeclarative.git] / src / quick / items / qquickwindowmanager.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
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.
16 **
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.
20 **
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.
28 **
29 ** Other Usage
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.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qquickwindowmanager_p.h"
43 #include "qquickthreadedwindowmanager_p.h"
44
45 #include <QtCore/QCoreApplication>
46 #include <QtCore/QTime>
47 #include <QtCore/private/qabstractanimation_p.h>
48
49 #include <QtGui/QOpenGLContext>
50 #include <QtGui/private/qguiapplication_p.h>
51 #include <qpa/qplatformintegration.h>
52
53 #include <QtQml/private/qqmlglobal_p.h>
54
55 #include <QtQuick/QQuickWindow>
56 #include <QtQuick/private/qquickwindow_p.h>
57 #include <QtQuick/private/qsgcontext_p.h>
58
59 QT_BEGIN_NAMESPACE
60
61 extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
62
63 /*!
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
70  */
71
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
74
75 QQuickWindowManager::~QQuickWindowManager()
76 {
77 }
78
79 class QQuickTrivialWindowManager : public QObject, public QQuickWindowManager
80 {
81     Q_OBJECT
82 public:
83     QQuickTrivialWindowManager();
84
85     void show(QQuickWindow *window);
86     void hide(QQuickWindow *window);
87
88     void windowDestroyed(QQuickWindow *window);
89
90     void initializeGL();
91     void renderWindow(QQuickWindow *window);
92     void exposureChanged(QQuickWindow *window);
93     QImage grab(QQuickWindow *window);
94     void resize(QQuickWindow *window, const QSize &size);
95     void wakeup();
96
97     void maybeUpdate(QQuickWindow *window);
98     void update(QQuickWindow *window) { maybeUpdate(window); } // identical for this implementation.
99
100     void releaseResources() { }
101
102     volatile bool *allowMainThreadProcessing();
103
104     QSGContext *sceneGraphContext() const;
105
106     bool event(QEvent *);
107
108     struct WindowData {
109         bool updatePending : 1;
110         bool grabOnly : 1;
111     };
112
113     QHash<QQuickWindow *, WindowData> m_windows;
114
115     QOpenGLContext *gl;
116     QSGContext *sg;
117
118     QImage grabContent;
119
120     bool eventPending;
121 };
122
123
124 QQuickWindowManager *QQuickWindowManager::instance()
125 {
126     static QQuickWindowManager *theInstance;
127
128     if (!theInstance) {
129
130         theInstance = QSGContext::createWindowManager();
131
132         bool bufferQueuing = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::BufferQueueingOpenGL);
133         bool fancy = bufferQueuing
134             && QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedOpenGL);
135         if (qmlNoThreadedRenderer())
136             fancy = false;
137         else if (qmlForceThreadedRenderer())
138             fancy = true;
139
140         // Enable fixed animation steps...
141         QByteArray fixed = qgetenv("QML_FIXED_ANIMATION_STEP");
142         bool fixedAnimationSteps = bufferQueuing;
143         if (fixed == "no")
144             fixedAnimationSteps = false;
145         else if (fixed.length())
146             fixedAnimationSteps = true;
147         if (fixedAnimationSteps)
148             QUnifiedTimer::instance(true)->setConsistentTiming(true);
149
150         if (!theInstance) {
151             theInstance = fancy
152                     ? (QQuickWindowManager*) new QQuickRenderThreadSingleContextWindowManager
153                     : (QQuickWindowManager*) new QQuickTrivialWindowManager;
154         }
155     }
156     return theInstance;
157 }
158
159 QQuickTrivialWindowManager::QQuickTrivialWindowManager()
160     : gl(0)
161     , eventPending(false)
162 {
163     sg = QSGContext::createDefaultContext();
164 }
165
166
167 void QQuickTrivialWindowManager::show(QQuickWindow *window)
168 {
169     WindowData data;
170     data.updatePending = false;
171     data.grabOnly = false;
172     m_windows[window] = data;
173
174     maybeUpdate(window);
175 }
176
177 void QQuickTrivialWindowManager::hide(QQuickWindow *window)
178 {
179     if (!m_windows.contains(window))
180         return;
181
182     m_windows.remove(window);
183     QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
184     cd->cleanupNodesOnShutdown();
185
186     if (m_windows.size() == 0) {
187         sg->invalidate();
188         delete gl;
189         gl = 0;
190     }
191 }
192
193 void QQuickTrivialWindowManager::windowDestroyed(QQuickWindow *window)
194 {
195     hide(window);
196 }
197
198 void QQuickTrivialWindowManager::renderWindow(QQuickWindow *window)
199 {
200     if (!window->isExposed() || !m_windows.contains(window))
201         return;
202
203     WindowData &data = const_cast<WindowData &>(m_windows[window]);
204
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();
212         }
213     } else {
214         masterWindow = window;
215     }
216
217     if (!masterWindow)
218         return;
219
220     if (!gl) {
221         gl = new QOpenGLContext();
222         gl->setFormat(masterWindow->requestedFormat());
223         gl->create();
224         if (!gl->makeCurrent(masterWindow))
225             qWarning("QQuickWindow: makeCurrent() failed...");
226         sg->initialize(gl);
227     } else {
228         gl->makeCurrent(masterWindow);
229     }
230
231     bool alsoSwap = data.updatePending;
232     data.updatePending = false;
233
234     QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
235     cd->polishItems();
236     cd->syncSceneGraph();
237     cd->renderSceneGraph(window->size());
238
239     if (data.grabOnly) {
240         grabContent = qt_gl_read_framebuffer(window->size(), false, false);
241         data.grabOnly = false;
242     }
243
244     if (alsoSwap && window->isVisible()) {
245         gl->swapBuffers(window);
246         cd->fireFrameSwapped();
247     }
248
249     // Might have been set during syncSceneGraph()
250     if (data.updatePending)
251         maybeUpdate(window);
252 }
253
254 void QQuickTrivialWindowManager::exposureChanged(QQuickWindow *window)
255 {
256     if (window->isExposed())
257         maybeUpdate(window);
258 }
259
260 QImage QQuickTrivialWindowManager::grab(QQuickWindow *window)
261 {
262     if (!m_windows.contains(window))
263         return QImage();
264
265     m_windows[window].grabOnly = true;
266
267     renderWindow(window);
268
269     QImage grabbed = grabContent;
270     grabContent = QImage();
271     return grabbed;
272 }
273
274
275
276 void QQuickTrivialWindowManager::resize(QQuickWindow *, const QSize &)
277 {
278 }
279
280
281
282 void QQuickTrivialWindowManager::maybeUpdate(QQuickWindow *window)
283 {
284     if (!m_windows.contains(window))
285         return;
286
287     m_windows[window].updatePending = true;
288
289     if (!eventPending) {
290         QCoreApplication::postEvent(this, new QEvent(QEvent::User));
291         eventPending = true;
292     }
293 }
294
295 void QQuickTrivialWindowManager::wakeup()
296 {
297 }
298
299 volatile bool *QQuickTrivialWindowManager::allowMainThreadProcessing()
300 {
301     return 0;
302 }
303
304
305
306 QSGContext *QQuickTrivialWindowManager::sceneGraphContext() const
307 {
308     return sg;
309 }
310
311
312 bool QQuickTrivialWindowManager::event(QEvent *e)
313 {
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());
321         }
322         return true;
323     }
324     return QObject::event(e);
325 }
326
327 #include "qquickwindowmanager.moc"
328
329 QT_END_NAMESPACE