1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQuick module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qsgsoftwarerenderloop_p.h"
41
42#include "qsgsoftwarecontext_p.h"
43
44#include <QtCore/QCoreApplication>
45
46#include <private/qquickwindow_p.h>
47#include <QElapsedTimer>
48#include <private/qquickanimatorcontroller_p.h>
49#include <private/qquickprofiler_p.h>
50#include <private/qsgsoftwarerenderer_p.h>
51#include <qpa/qplatformbackingstore.h>
52
53#include <QtGui/QBackingStore>
54
55#include <qtquick_tracepoints_p.h>
56
57QT_BEGIN_NAMESPACE
58
59QSGSoftwareRenderLoop::QSGSoftwareRenderLoop()
60{
61 sg = new QSGSoftwareContext();
62 rc = sg->createRenderContext();
63}
64
65QSGSoftwareRenderLoop::~QSGSoftwareRenderLoop()
66{
67 delete rc;
68 delete sg;
69}
70
71void QSGSoftwareRenderLoop::show(QQuickWindow *window)
72{
73 WindowData data;
74 data.updatePending = false;
75 data.grabOnly = false;
76 m_windows[window] = data;
77
78 if (m_backingStores[window] == nullptr) {
79 m_backingStores[window] = new QBackingStore(window);
80 }
81
82 maybeUpdate(window);
83}
84
85void QSGSoftwareRenderLoop::hide(QQuickWindow *window)
86{
87 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(c: window);
88 cd->fireAboutToStop();
89}
90
91void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window)
92{
93 m_windows.remove(key: window);
94 delete m_backingStores[window];
95 m_backingStores.remove(key: window);
96 hide(window);
97
98 QQuickWindowPrivate *d = QQuickWindowPrivate::get(c: window);
99 d->cleanupNodesOnShutdown();
100
101 if (m_windows.size() == 0) {
102 rc->invalidate();
103 }
104
105 d->animationController.reset();
106}
107
108void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
109{
110 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(c: window);
111 if (!m_windows.contains(key: window))
112 return;
113
114 WindowData &data = const_cast<WindowData &>(m_windows[window]);
115
116 //If were not in grabOnly mode, dont render a non-renderable window
117 if (!data.grabOnly && !cd->isRenderable())
118 return;
119
120 //Resize the backing store if necessary
121 if (m_backingStores[window]->size() != window->size()) {
122 m_backingStores[window]->resize(size: window->size());
123 }
124
125 // ### create QPainter and set up pointer to current window/painter
126 QSGSoftwareRenderContext *ctx = static_cast<QSGSoftwareRenderContext*>(cd->context);
127 ctx->initializeIfNeeded();
128
129 bool alsoSwap = data.updatePending;
130 data.updatePending = false;
131
132 if (!data.grabOnly) {
133 cd->flushFrameSynchronousEvents();
134 // Event delivery/processing triggered the window to be deleted or stop rendering.
135 if (!m_windows.contains(key: window))
136 return;
137 }
138
139 Q_TRACE_SCOPE(QSG_renderWindow)
140 QElapsedTimer renderTimer;
141 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
142 bool profileFrames = QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled();
143 if (profileFrames)
144 renderTimer.start();
145 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
146 Q_TRACE(QSG_polishItems_entry);
147
148 cd->polishItems();
149
150 if (profileFrames)
151 polishTime = renderTimer.nsecsElapsed();
152 Q_TRACE(QSG_polishItems_exit);
153 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
154 QQuickProfiler::SceneGraphRenderLoopFrame,
155 QQuickProfiler::SceneGraphPolishPolish);
156 Q_TRACE(QSG_sync_entry);
157
158 emit window->afterAnimating();
159
160 cd->syncSceneGraph();
161 rc->endSync();
162
163 if (profileFrames)
164 syncTime = renderTimer.nsecsElapsed();
165 Q_TRACE(QSG_sync_exit);
166 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
167 QQuickProfiler::SceneGraphRenderLoopSync);
168 Q_TRACE(QSG_render_entry);
169
170 //Tell the renderer about the windows backing store
171 auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
172 if (softwareRenderer)
173 softwareRenderer->setBackingStore(m_backingStores[window]);
174
175 cd->renderSceneGraph(size: window->size());
176
177 if (profileFrames)
178 renderTime = renderTimer.nsecsElapsed();
179 Q_TRACE(QSG_render_exit);
180 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
181 QQuickProfiler::SceneGraphRenderLoopRender);
182 Q_TRACE(QSG_swap_entry);
183
184 if (data.grabOnly) {
185 grabContent = m_backingStores[window]->handle()->toImage();
186 data.grabOnly = false;
187 }
188
189 if (alsoSwap && window->isVisible()) {
190 //Flush backingstore to window
191 if (!isNewExpose)
192 m_backingStores[window]->flush(region: softwareRenderer->flushRegion());
193 else
194 m_backingStores[window]->flush(region: QRegion(QRect(QPoint(0,0), window->size())));
195 cd->fireFrameSwapped();
196 }
197
198 qint64 swapTime = 0;
199 if (profileFrames)
200 swapTime = renderTimer.nsecsElapsed();
201 Q_TRACE(QSG_swap_exit);
202 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
203 QQuickProfiler::SceneGraphRenderLoopSwap);
204
205 if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
206 static QTime lastFrameTime = QTime::currentTime();
207 qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP,
208 "Frame rendered with 'software' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
209 int(swapTime / 1000000),
210 int(polishTime / 1000000),
211 int((syncTime - polishTime) / 1000000),
212 int((renderTime - syncTime) / 1000000),
213 int((swapTime - renderTime) / 1000000),
214 int(lastFrameTime.msecsTo(QTime::currentTime())));
215 lastFrameTime = QTime::currentTime();
216 }
217
218 // Might have been set during syncSceneGraph()
219 if (data.updatePending)
220 maybeUpdate(window);
221}
222
223void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window)
224{
225 if (window->isExposed()) {
226 m_windows[window].updatePending = true;
227 renderWindow(window, isNewExpose: true);
228 }
229}
230
231QImage QSGSoftwareRenderLoop::grab(QQuickWindow *window)
232{
233 //If the window was never shown, create a new backing store
234 if (!m_backingStores.contains(key: window)) {
235 m_backingStores[window] = new QBackingStore(window);
236 // Call create on window to make sure platform window is created
237 window->create();
238 }
239
240 //If there is no WindowData, add one
241 if (!m_windows.contains(key: window)) {
242 WindowData data;
243 data.updatePending = false;
244 m_windows[window] = data;
245 }
246
247 m_windows[window].grabOnly = true;
248
249 renderWindow(window);
250
251 QImage grabbed = grabContent;
252 grabbed.detach();
253 grabContent = QImage();
254 return grabbed;
255}
256
257
258
259void QSGSoftwareRenderLoop::maybeUpdate(QQuickWindow *window)
260{
261 if (!m_windows.contains(key: window))
262 return;
263
264 m_windows[window].updatePending = true;
265 window->requestUpdate();
266}
267
268QSurface::SurfaceType QSGSoftwareRenderLoop::windowSurfaceType() const
269{
270 return QSurface::RasterSurface;
271}
272
273
274
275QSGContext *QSGSoftwareRenderLoop::sceneGraphContext() const
276{
277 return sg;
278}
279
280
281void QSGSoftwareRenderLoop::handleUpdateRequest(QQuickWindow *window)
282{
283 renderWindow(window);
284}
285
286QT_END_NAMESPACE
287
288#include "moc_qsgsoftwarerenderloop_p.cpp"
289

source code of qtdeclarative/src/quick/scenegraph/adaptations/software/qsgsoftwarerenderloop.cpp