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 "qsgopenvgrenderloop_p.h"
41 #include "qsgopenvgcontext_p.h"
42
43 #include <QtCore/QCoreApplication>
44 #include <QtCore/QElapsedTimer>
45
46 #include <private/qquickanimatorcontroller_p.h>
47 #include <private/qquickwindow_p.h>
48 #include <private/qquickprofiler_p.h>
49
50 #include <qtquick_tracepoints_p.h>
51
52 #include "qopenvgcontext_p.h"
53
54 QT_BEGIN_NAMESPACE
55
QSGOpenVGRenderLoop()56 QSGOpenVGRenderLoop::QSGOpenVGRenderLoop()
57 : vg(nullptr)
58 {
59 sg = QSGContext::createDefaultContext();
60 rc = sg->createRenderContext();
61 }
62
~QSGOpenVGRenderLoop()63 QSGOpenVGRenderLoop::~QSGOpenVGRenderLoop()
64 {
65 delete rc;
66 delete sg;
67 }
68
show(QQuickWindow * window)69 void QSGOpenVGRenderLoop::show(QQuickWindow *window)
70 {
71 WindowData data;
72 data.updatePending = false;
73 data.grabOnly = false;
74 m_windows[window] = data;
75
76 maybeUpdate(window);
77 }
78
hide(QQuickWindow * window)79 void QSGOpenVGRenderLoop::hide(QQuickWindow *window)
80 {
81 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
82 cd->fireAboutToStop();
83 }
84
windowDestroyed(QQuickWindow * window)85 void QSGOpenVGRenderLoop::windowDestroyed(QQuickWindow *window)
86 {
87 m_windows.remove(window);
88 hide(window);
89
90 QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
91 d->cleanupNodesOnShutdown();
92
93 if (m_windows.size() == 0) {
94 rc->invalidate();
95 delete vg;
96 vg = nullptr;
97 } else if (vg && window == vg->window()) {
98 vg->doneCurrent();
99 }
100
101 d->animationController.reset();
102 }
103
exposureChanged(QQuickWindow * window)104 void QSGOpenVGRenderLoop::exposureChanged(QQuickWindow *window)
105 {
106 if (window->isExposed()) {
107 m_windows[window].updatePending = true;
108 renderWindow(window);
109 }
110 }
111
grab(QQuickWindow * window)112 QImage QSGOpenVGRenderLoop::grab(QQuickWindow *window)
113 {
114 if (!m_windows.contains(window))
115 return QImage();
116
117 m_windows[window].grabOnly = true;
118
119 renderWindow(window);
120
121 QImage grabbed = grabContent;
122 grabContent = QImage();
123 return grabbed;
124 }
125
update(QQuickWindow * window)126 void QSGOpenVGRenderLoop::update(QQuickWindow *window)
127 {
128 maybeUpdate(window);
129 }
130
handleUpdateRequest(QQuickWindow * window)131 void QSGOpenVGRenderLoop::handleUpdateRequest(QQuickWindow *window)
132 {
133 renderWindow(window);
134 }
135
maybeUpdate(QQuickWindow * window)136 void QSGOpenVGRenderLoop::maybeUpdate(QQuickWindow *window)
137 {
138 if (!m_windows.contains(window))
139 return;
140
141 m_windows[window].updatePending = true;
142 window->requestUpdate();
143 }
144
animationDriver() const145 QAnimationDriver *QSGOpenVGRenderLoop::animationDriver() const
146 {
147 return nullptr;
148 }
149
sceneGraphContext() const150 QSGContext *QSGOpenVGRenderLoop::sceneGraphContext() const
151 {
152 return sg;
153 }
154
createRenderContext(QSGContext *) const155 QSGRenderContext *QSGOpenVGRenderLoop::createRenderContext(QSGContext *) const
156 {
157 return rc;
158 }
159
releaseResources(QQuickWindow * window)160 void QSGOpenVGRenderLoop::releaseResources(QQuickWindow *window)
161 {
162 Q_UNUSED(window)
163 }
164
windowSurfaceType() const165 QSurface::SurfaceType QSGOpenVGRenderLoop::windowSurfaceType() const
166 {
167 return QSurface::OpenVGSurface;
168 }
169
renderWindow(QQuickWindow * window)170 void QSGOpenVGRenderLoop::renderWindow(QQuickWindow *window)
171 {
172 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
173 if (!cd->isRenderable() || !m_windows.contains(window))
174 return;
175
176 Q_TRACE_SCOPE(QSG_renderWindow);
177
178 WindowData &data = const_cast<WindowData &>(m_windows[window]);
179
180 if (vg == nullptr) {
181 vg = new QOpenVGContext(window);
182 vg->makeCurrent();
183 QSGOpenVGRenderContext::InitParams params;
184 params.context = vg;
185 cd->context->initialize(¶ms);
186 } else {
187 vg->makeCurrent();
188 }
189
190 bool alsoSwap = data.updatePending;
191 data.updatePending = false;
192
193 if (!data.grabOnly) {
194 cd->flushFrameSynchronousEvents();
195 // Event delivery/processing triggered the window to be deleted or stop rendering.
196 if (!m_windows.contains(window))
197 return;
198 }
199 QElapsedTimer renderTimer;
200 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
201 bool profileFrames = QSG_OPENVG_LOG_TIME_RENDERLOOP().isDebugEnabled();
202 if (profileFrames)
203 renderTimer.start();
204 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
205 Q_TRACE(QSG_polishItems_entry);
206
207 cd->polishItems();
208
209 if (profileFrames)
210 polishTime = renderTimer.nsecsElapsed();
211 Q_TRACE(QSG_polishItems_exit);
212 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
213 QQuickProfiler::SceneGraphRenderLoopFrame,
214 QQuickProfiler::SceneGraphPolishPolish);
215 Q_TRACE(QSG_sync_entry);
216
217 emit window->afterAnimating();
218
219 cd->syncSceneGraph();
220 rc->endSync();
221
222 if (profileFrames)
223 syncTime = renderTimer.nsecsElapsed();
224 Q_TRACE(QSG_sync_exit);
225 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
226 QQuickProfiler::SceneGraphRenderLoopSync);
227 Q_TRACE(QSG_render_entry);
228
229 // setup coordinate system for window
230 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
231 vgLoadIdentity();
232 vgTranslate(0.0f, window->size().height());
233 vgScale(1.0, -1.0);
234
235 cd->renderSceneGraph(window->size());
236
237 if (profileFrames)
238 renderTime = renderTimer.nsecsElapsed();
239 Q_TRACE(QSG_render_exit);
240 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
241 QQuickProfiler::SceneGraphRenderLoopRender);
242 Q_TRACE(QSG_swap_entry);
243
244 if (data.grabOnly) {
245 grabContent = vg->readFramebuffer(window->size() * window->effectiveDevicePixelRatio());
246 data.grabOnly = false;
247 }
248
249 if (alsoSwap && window->isVisible()) {
250 vg->swapBuffers();
251 cd->fireFrameSwapped();
252 }
253
254 qint64 swapTime = 0;
255 if (profileFrames)
256 swapTime = renderTimer.nsecsElapsed();
257 Q_TRACE(QSG_swap_exit);
258 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
259 QQuickProfiler::SceneGraphRenderLoopSwap);
260
261 if (QSG_OPENVG_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
262 static QTime lastFrameTime = QTime::currentTime();
263 qCDebug(QSG_OPENVG_LOG_TIME_RENDERLOOP,
264 "Frame rendered with 'basic' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
265 int(swapTime / 1000000),
266 int(polishTime / 1000000),
267 int((syncTime - polishTime) / 1000000),
268 int((renderTime - syncTime) / 1000000),
269 int((swapTime - renderTime) / 10000000),
270 int(lastFrameTime.msecsTo(QTime::currentTime())));
271 lastFrameTime = QTime::currentTime();
272 }
273
274 // Might have been set during syncSceneGraph()
275 if (data.updatePending)
276 maybeUpdate(window);
277 }
278
279 QT_END_NAMESPACE
280