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