Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qsgsoftwarerenderloop.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6
8
9#include <QtCore/QCoreApplication>
10
11#include <private/qquickwindow_p.h>
12#include <private/qquickitem_p.h>
13#include <QElapsedTimer>
14#include <private/qquickanimatorcontroller_p.h>
15#include <private/qquickprofiler_p.h>
16#include <private/qsgsoftwarerenderer_p.h>
17#include <qpa/qplatformbackingstore.h>
18
19#include <QtGui/QBackingStore>
20
21#include <qtquick_tracepoints_p.h>
22
24
25// polish, animations, sync, render and swap in the render loop
26Q_STATIC_LOGGING_CATEGORY(QSG_RASTER_LOG_TIME_RENDERLOOP, "qt.scenegraph.time.renderloop")
27
28QSGSoftwareRenderLoop::QSGSoftwareRenderLoop()
29{
30 sg = new QSGSoftwareContext();
31 rc = sg->createRenderContext();
32}
33
35{
36 delete rc;
37 delete sg;
38}
39
40void QSGSoftwareRenderLoop::show(QQuickWindow *window)
41{
42 WindowData data;
43 data.updatePending = false;
44 data.grabOnly = false;
45 m_windows[window] = data;
46
47 if (m_backingStores[window] == nullptr) {
48 m_backingStores[window] = new QBackingStore(window);
49 }
50
51 maybeUpdate(window);
52}
53
54void QSGSoftwareRenderLoop::hide(QQuickWindow *window)
55{
56 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
57 cd->fireAboutToStop();
58}
59
60void QSGSoftwareRenderLoop::windowDestroyed(QQuickWindow *window)
61{
62 m_windows.remove(window);
63 delete m_backingStores[window];
64 m_backingStores.remove(window);
65 hide(window);
66
67 QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
68 d->cleanupNodesOnShutdown();
69
70 if (m_windows.size() == 0) {
71 rc->invalidate();
72 }
73
74 d->animationController.reset();
75}
76
77void QSGSoftwareRenderLoop::renderWindow(QQuickWindow *window, bool isNewExpose)
78{
79 QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
80 if (!m_windows.contains(window))
81 return;
82
83 WindowData &data = const_cast<WindowData &>(m_windows[window]);
84
85 //If were not in grabOnly mode, dont render a non-renderable window
86 if (!data.grabOnly && !cd->isRenderable())
87 return;
88
89 //Resize the backing store if necessary
90 if (m_backingStores[window]->size() != window->size()) {
91 m_backingStores[window]->resize(window->size());
92 }
93
94 // ### create QPainter and set up pointer to current window/painter
95 QSGSoftwareRenderContext *ctx = static_cast<QSGSoftwareRenderContext*>(cd->context);
96 ctx->initializeIfNeeded();
97
98 bool alsoSwap = data.updatePending;
99 data.updatePending = false;
100
101 if (!data.grabOnly) {
102 cd->deliveryAgentPrivate()->flushFrameSynchronousEvents(window);
103 // Event delivery/processing triggered the window to be deleted or stop rendering.
104 if (!m_windows.contains(window))
105 return;
106 }
107
108 Q_TRACE_SCOPE(QSG_renderWindow)
109 QElapsedTimer renderTimer;
110 qint64 renderTime = 0, syncTime = 0, polishTime = 0;
111 bool profileFrames = QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled();
112 if (profileFrames)
113 renderTimer.start();
114 Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphPolishFrame);
115 Q_TRACE(QSG_polishItems_entry);
116
117 cd->polishItems();
118
119 if (profileFrames)
120 polishTime = renderTimer.nsecsElapsed();
121 Q_TRACE(QSG_polishItems_exit);
122 Q_QUICK_SG_PROFILE_SWITCH(QQuickProfiler::SceneGraphPolishFrame,
123 QQuickProfiler::SceneGraphRenderLoopFrame,
124 QQuickProfiler::SceneGraphPolishPolish);
125 Q_TRACE(QSG_sync_entry);
126
127 emit window->afterAnimating();
128
129 emit window->beforeFrameBegin();
130
131 cd->syncSceneGraph();
132 rc->endSync();
133
134 if (profileFrames)
135 syncTime = renderTimer.nsecsElapsed();
136 Q_TRACE(QSG_sync_exit);
137 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
138 QQuickProfiler::SceneGraphRenderLoopSync);
139 Q_TRACE(QSG_render_entry);
140
141 //Tell the renderer about the windows backing store
142 auto softwareRenderer = static_cast<QSGSoftwareRenderer*>(cd->renderer);
143 if (softwareRenderer)
144 softwareRenderer->setBackingStore(m_backingStores[window]);
145
146 cd->renderSceneGraph();
147
148 if (profileFrames)
149 renderTime = renderTimer.nsecsElapsed();
150 Q_TRACE(QSG_render_exit);
151 Q_QUICK_SG_PROFILE_RECORD(QQuickProfiler::SceneGraphRenderLoopFrame,
152 QQuickProfiler::SceneGraphRenderLoopRender);
153 Q_TRACE(QSG_swap_entry);
154
155 if (data.grabOnly) {
156 grabContent = m_backingStores[window]->handle()->toImage();
157 data.grabOnly = false;
158 }
159
160 if (alsoSwap && window->isVisible()) {
161 //Flush backingstore to window
162 if (!isNewExpose)
163 m_backingStores[window]->flush(softwareRenderer->flushRegion());
164 else
165 m_backingStores[window]->flush(QRegion(QRect(QPoint(0,0), window->size())));
166 cd->fireFrameSwapped();
167 }
168
169 emit window->afterFrameEnd();
170
171 qint64 swapTime = 0;
172 if (profileFrames)
173 swapTime = renderTimer.nsecsElapsed();
174 Q_TRACE(QSG_swap_exit);
175 Q_QUICK_SG_PROFILE_END(QQuickProfiler::SceneGraphRenderLoopFrame,
176 QQuickProfiler::SceneGraphRenderLoopSwap);
177
178 if (QSG_RASTER_LOG_TIME_RENDERLOOP().isDebugEnabled()) {
179 static QTime lastFrameTime = QTime::currentTime();
180 qCDebug(QSG_RASTER_LOG_TIME_RENDERLOOP,
181 "Frame rendered with 'software' renderloop in %dms, polish=%d, sync=%d, render=%d, swap=%d, frameDelta=%d",
182 int(swapTime / 1000000),
183 int(polishTime / 1000000),
184 int((syncTime - polishTime) / 1000000),
185 int((renderTime - syncTime) / 1000000),
186 int((swapTime - renderTime) / 1000000),
187 int(lastFrameTime.msecsTo(QTime::currentTime())));
188 lastFrameTime = QTime::currentTime();
189 }
190
191 // Might have been set during syncSceneGraph()
192 if (data.updatePending)
193 maybeUpdate(window);
194}
195
196void QSGSoftwareRenderLoop::exposureChanged(QQuickWindow *window)
197{
198 if (window->isExposed()) {
199 m_windows[window].updatePending = true;
200 renderWindow(window, true);
201 }
202}
203
204QImage QSGSoftwareRenderLoop::grab(QQuickWindow *window)
205{
206 //If the window was never shown, create a new backing store
207 if (!m_backingStores.contains(window)) {
208 m_backingStores[window] = new QBackingStore(window);
209 // Call create on window to make sure platform window is created
210 window->create();
211 }
212
213 //If there is no WindowData, add one
214 if (!m_windows.contains(window)) {
215 WindowData data;
216 data.updatePending = false;
217 m_windows[window] = data;
218 }
219
220 m_windows[window].grabOnly = true;
221
222 renderWindow(window);
223
224 QImage grabbed = grabContent;
225 grabbed.detach();
226 grabContent = QImage();
227 return grabbed;
228}
229
230
231
232void QSGSoftwareRenderLoop::maybeUpdate(QQuickWindow *window)
233{
234 if (!m_windows.contains(window))
235 return;
236
237 m_windows[window].updatePending = true;
238 window->requestUpdate();
239}
240
242{
243 return QSurface::RasterSurface;
244}
245
246
247
249{
250 return sg;
251}
252
253
255{
256 renderWindow(window);
257}
258
259QT_END_NAMESPACE
260
261#include "moc_qsgsoftwarerenderloop_p.cpp"
QImage grab(QQuickWindow *window) override
void exposureChanged(QQuickWindow *window) override
void maybeUpdate(QQuickWindow *window) override
QSGContext * sceneGraphContext() const override
void show(QQuickWindow *window) override
void hide(QQuickWindow *window) override
void handleUpdateRequest(QQuickWindow *) override
void windowDestroyed(QQuickWindow *window) override
QSurface::SurfaceType windowSurfaceType() const override
void renderWindow(QQuickWindow *window, bool isNewExpose=false)
Combined button and popup list for selecting options.