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