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 "qsgsoftwarelayer_p.h"
5
6#include "qsgsoftwarecontext_p.h"
7#include "qsgsoftwarepixmaprenderer_p.h"
8
9QT_BEGIN_NAMESPACE
10
11QSGSoftwareLayer::QSGSoftwareLayer(QSGRenderContext *renderContext)
12 : QSGLayer(*(new QSGTexturePrivate(this)))
13 , m_item(nullptr)
14 , m_context(renderContext)
15 , m_renderer(nullptr)
16 , m_device_pixel_ratio(1)
17 , m_mirrorHorizontal(false)
18 , m_mirrorVertical(true)
19 , m_live(true)
20 , m_grab(true)
21 , m_recursive(false)
22 , m_dirtyTexture(true)
23{
24
25}
26
27QSGSoftwareLayer::~QSGSoftwareLayer()
28{
29 invalidated();
30}
31
32qint64 QSGSoftwareLayer::comparisonKey() const
33{
34 return 0;
35}
36
37QSize QSGSoftwareLayer::textureSize() const
38{
39 return m_pixmap.size();
40}
41
42bool QSGSoftwareLayer::hasAlphaChannel() const
43{
44 return m_pixmap.hasAlphaChannel();
45}
46
47bool QSGSoftwareLayer::hasMipmaps() const
48{
49 return false;
50}
51
52bool QSGSoftwareLayer::updateTexture()
53{
54 bool doGrab = (m_live || m_grab) && m_dirtyTexture;
55 if (doGrab)
56 grab();
57 if (m_grab)
58 emit scheduledUpdateCompleted();
59 m_grab = false;
60 return doGrab;
61}
62
63void QSGSoftwareLayer::setItem(QSGNode *item)
64{
65 if (item == m_item)
66 return;
67 m_item = item;
68
69 if (m_live && !m_item)
70 m_pixmap = QPixmap();
71
72 markDirtyTexture();
73}
74
75void QSGSoftwareLayer::setRect(const QRectF &rect)
76{
77 if (rect == m_rect)
78 return;
79 m_rect = rect;
80 markDirtyTexture();
81}
82
83void QSGSoftwareLayer::setSize(const QSize &size)
84{
85 if (size == m_size)
86 return;
87 m_size = size;
88
89 if (m_live && m_size.isNull())
90 m_pixmap = QPixmap();
91
92 markDirtyTexture();
93}
94
95void QSGSoftwareLayer::scheduleUpdate()
96{
97 if (m_grab)
98 return;
99 m_grab = true;
100 if (m_dirtyTexture) {
101 emit updateRequested();
102 }
103}
104
105QImage QSGSoftwareLayer::toImage() const
106{
107 return m_pixmap.toImage();
108}
109
110void QSGSoftwareLayer::setLive(bool live)
111{
112 if (live == m_live)
113 return;
114 m_live = live;
115
116 if (m_live && (!m_item || m_size.isNull()))
117 m_pixmap = QPixmap();
118
119 markDirtyTexture();
120}
121
122void QSGSoftwareLayer::setRecursive(bool recursive)
123{
124 m_recursive = recursive;
125}
126
127void QSGSoftwareLayer::setFormat(Format)
128{
129}
130
131void QSGSoftwareLayer::setHasMipmaps(bool)
132{
133}
134
135void QSGSoftwareLayer::setDevicePixelRatio(qreal ratio)
136{
137 m_device_pixel_ratio = ratio;
138}
139
140void QSGSoftwareLayer::setMirrorHorizontal(bool mirror)
141{
142 if (m_mirrorHorizontal == mirror)
143 return;
144 m_mirrorHorizontal = mirror;
145 markDirtyTexture();
146}
147
148void QSGSoftwareLayer::setMirrorVertical(bool mirror)
149{
150 if (m_mirrorVertical == mirror)
151 return;
152 m_mirrorVertical = mirror;
153 markDirtyTexture();
154}
155
156void QSGSoftwareLayer::markDirtyTexture()
157{
158 m_dirtyTexture = true;
159 if (m_live || m_grab) {
160 emit updateRequested();
161 }
162}
163
164void QSGSoftwareLayer::invalidated()
165{
166 delete m_renderer;
167 m_renderer = nullptr;
168}
169
170void QSGSoftwareLayer::grab()
171{
172 if (!m_item || m_size.isNull()) {
173 m_pixmap = QPixmap();
174 m_dirtyTexture = false;
175 return;
176 }
177 QSGNode *root = m_item;
178 while (root->firstChild() && root->type() != QSGNode::RootNodeType)
179 root = root->firstChild();
180 if (root->type() != QSGNode::RootNodeType)
181 return;
182
183 if (!m_renderer) {
184 m_renderer = new QSGSoftwarePixmapRenderer(m_context);
185 connect(sender: m_renderer, SIGNAL(sceneGraphChanged()), receiver: this, SLOT(markDirtyTexture()));
186 }
187 m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
188 m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
189
190 if (m_pixmap.size() != m_size) {
191 m_pixmap = QPixmap(m_size);
192 m_pixmap.setDevicePixelRatio(m_device_pixel_ratio);
193 }
194
195 // Render texture.
196 root->markDirty(bits: QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
197 m_renderer->nodeChanged(node: root, state: QSGNode::DirtyForceUpdate); // Force render list update.
198
199 m_dirtyTexture = false;
200
201 m_renderer->setDeviceRect(m_size);
202 m_renderer->setViewportRect(m_size);
203 QRect mirrored(m_mirrorHorizontal ? m_rect.right() * m_device_pixel_ratio : m_rect.left() * m_device_pixel_ratio,
204 m_mirrorVertical ? m_rect.bottom() * m_device_pixel_ratio : m_rect.top() * m_device_pixel_ratio,
205 m_mirrorHorizontal ? -m_rect.width() * m_device_pixel_ratio : m_rect.width() * m_device_pixel_ratio,
206 m_mirrorVertical ? -m_rect.height() * m_device_pixel_ratio : m_rect.height() * m_device_pixel_ratio);
207 m_renderer->setProjectionRect(mirrored);
208 m_renderer->setClearColor(Qt::transparent);
209
210 m_renderer->renderScene();
211 m_renderer->render(target: &m_pixmap);
212
213 root->markDirty(bits: QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
214
215 if (m_recursive)
216 markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
217}
218
219QT_END_NAMESPACE
220
221#include "moc_qsgsoftwarelayer_p.cpp"
222

source code of qtdeclarative/src/quick/scenegraph/adaptations/software/qsgsoftwarelayer.cpp