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