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
qsgsoftwarerenderer.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
11
12#include <QtGui/QPaintDevice>
13#include <QtGui/QBackingStore>
14#include <QElapsedTimer>
15
16Q_STATIC_LOGGING_CATEGORY(lcRenderer, "qt.scenegraph.softwarecontext.renderer")
17
18QT_BEGIN_NAMESPACE
19
20QSGSoftwareRenderer::QSGSoftwareRenderer(QSGRenderContext *context)
21 : QSGAbstractSoftwareRenderer(context)
22 , m_paintDevice(nullptr)
23 , m_backingStore(nullptr)
24{
25 // Check if the environment variable is set to force/disable partial updates
26 static bool partialUpdateOverrideSet = false;
27 static const int forcePartialUpdates = qEnvironmentVariableIntValue("QSG_SOFTWARE_RENDERER_FORCE_PARTIAL_UPDATES", &partialUpdateOverrideSet);
28 if (partialUpdateOverrideSet) {
29 if (forcePartialUpdates == 0)
30 m_partialUpdateMode = DisablePartialUpdate;
31 else
32 m_partialUpdateMode = ForcePartialUpdate;
33 }
34}
35
36QSGSoftwareRenderer::~QSGSoftwareRenderer()
37{
38}
39
40void QSGSoftwareRenderer::setCurrentPaintDevice(QPaintDevice *device)
41{
42 m_paintDevice = device;
43 m_backingStore = nullptr;
44}
45
46QPaintDevice *QSGSoftwareRenderer::currentPaintDevice() const
47{
48 return m_paintDevice;
49}
50
51void QSGSoftwareRenderer::setBackingStore(QBackingStore *backingStore)
52{
53 m_backingStore = backingStore;
54 m_paintDevice = nullptr;
55}
56
57QRegion QSGSoftwareRenderer::flushRegion() const
58{
59 return m_flushRegion;
60}
61
62void QSGSoftwareRenderer::renderScene()
63{
64 QSGRenderer::renderScene();
65}
66
67void QSGSoftwareRenderer::render()
68{
69 if (!m_paintDevice && !m_backingStore && !m_rt.paintDevice)
70 return;
71
72 QPaintDevice *paintDevice = m_paintDevice ? m_paintDevice : m_rt.paintDevice;
73 QSize paintSize;
74 qreal paintDevicePixelRatio = 1.0;
75
76 if (paintDevice) {
77 paintSize = QSize(paintDevice->width(), paintDevice->height());
78 paintDevicePixelRatio = paintDevice->devicePixelRatio();
79 } else {
80 // For HiDPI QBackingStores, the paint device is valid between calls to
81 // beginPaint() and endPaint(). See: QTBUG-55875
82
83 m_backingStore->beginPaint(QRegion());
84
85 const QPaintDevice *backingStorePaintDevice = m_backingStore->paintDevice();
86 paintSize = QSize(backingStorePaintDevice->width(), backingStorePaintDevice->height());
87 paintDevicePixelRatio = backingStorePaintDevice->devicePixelRatio();
88
89 m_backingStore->endPaint();
90 }
91
92 QElapsedTimer renderTimer;
93
94 setBackgroundColor(clearColor());
95 setBackgroundRect(QRect(0, 0,
96 paintSize.width() / paintDevicePixelRatio,
97 paintSize.height() / paintDevicePixelRatio),
98 paintDevicePixelRatio);
99 // If paintDevicePixelRatio is not a whole number, opt to disable the partial update mechanism
100 const bool nonIntegerRatio = !qFuzzyIsNull(paintDevicePixelRatio - qFloor(paintDevicePixelRatio));
101 bool disablePartialUpdates = m_partialUpdateMode == DisablePartialUpdate || nonIntegerRatio;
102 if (m_partialUpdateMode == ForcePartialUpdate)
103 disablePartialUpdates = false;
104
105 // Force the whole render area to be marked as dirty, avoiding any partial update
106 if (disablePartialUpdates)
107 markDirty();
108
109 // Build Renderlist
110 // The renderlist is created by visiting each node in the tree and when a
111 // renderable node is reach, we find the coorosponding RenderableNode object
112 // and append it to the renderlist. At this point the RenderableNode object
113 // should not need any further updating so it is just a matter of appending
114 // RenderableNodes
115 renderTimer.start();
116 buildRenderList();
117 qint64 buildRenderListTime = renderTimer.restart();
118
119 // Optimize Renderlist
120 // This is a pass through the renderlist to determine what actually needs to
121 // be painted. Without this pass the renderlist will simply render each item
122 // from back to front, with a high potential for overdraw. It would also lead
123 // to the entire window being flushed every frame. The objective of the
124 // optimization pass is to only paint dirty nodes that are not occuluded. A
125 // side effect of this is that additional nodes may need to be marked dirty to
126 // force a repaint. It is also important that any item that needs to be
127 // repainted only paints what is needed, via the use of clip regions.
128 const QRegion updateRegion = optimizeRenderList();
129 qint64 optimizeRenderListTime = renderTimer.restart();
130
131 // If Rendering to a backingstore, prepare it to be updated
132 bool usingBackingStore = false;
133 if (!paintDevice) {
134 m_backingStore->beginPaint(updateRegion);
135 paintDevice = m_backingStore->paintDevice();
136 usingBackingStore = true;
137 }
138
139 QPainter painter(paintDevice);
140 painter.setRenderHint(QPainter::Antialiasing);
141 auto rc = static_cast<QSGSoftwareRenderContext *>(context());
142 QPainter *prevPainter = rc->m_activePainter;
143 rc->m_activePainter = &painter;
144
145 // Render the contents Renderlist
146 m_flushRegion = renderNodes(&painter);
147 qint64 renderTime = renderTimer.elapsed();
148
149 painter.end();
150 if (usingBackingStore)
151 m_backingStore->endPaint();
152
153 rc->m_activePainter = prevPainter;
154 qCDebug(lcRenderer) << "render" << m_flushRegion << buildRenderListTime << optimizeRenderListTime << renderTime;
155}
156
157QT_END_NAMESPACE
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)