1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQuick module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qsgopenvglayer.h"
41 #include "qsgopenvgrenderer_p.h"
42 #include "qsgopenvgcontext_p.h"
43
44 QT_BEGIN_NAMESPACE
45
QSGOpenVGLayer(QSGRenderContext * renderContext)46 QSGOpenVGLayer::QSGOpenVGLayer(QSGRenderContext *renderContext)
47 : QSGLayer(*(new QSGOpenVGLayerPrivate))
48 , m_item(nullptr)
49 , m_renderer(nullptr)
50 , m_device_pixel_ratio(1)
51 , m_mirrorHorizontal(false)
52 , m_mirrorVertical(false)
53 , m_live(true)
54 , m_grab(true)
55 , m_recursive(false)
56 , m_dirtyTexture(true)
57 , m_offscreenSurface(nullptr)
58 , m_secondaryOffscreenSurface(nullptr)
59 {
60 m_context = static_cast<QSGOpenVGRenderContext*>(renderContext);
61 }
62
~QSGOpenVGLayer()63 QSGOpenVGLayer::~QSGOpenVGLayer()
64 {
65 invalidated();
66 }
67
textureId() const68 int QSGOpenVGLayer::textureId() const
69 {
70 if (m_offscreenSurface)
71 return static_cast<int>(m_offscreenSurface->image());
72 else
73 return 0;
74 }
75
textureSize() const76 QSize QSGOpenVGLayer::textureSize() const
77 {
78 if (m_offscreenSurface) {
79 return m_offscreenSurface->size();
80 }
81
82 return QSize();
83 }
84
hasAlphaChannel() const85 bool QSGOpenVGLayer::hasAlphaChannel() const
86 {
87 return true;
88 }
89
hasMipmaps() const90 bool QSGOpenVGLayer::hasMipmaps() const
91 {
92 return false;
93 }
94
bind()95 void QSGOpenVGLayer::bind()
96 {
97 }
98
updateTexture()99 bool QSGOpenVGLayer::updateTexture()
100 {
101 bool doGrab = (m_live || m_grab) && m_dirtyTexture;
102 if (doGrab)
103 grab();
104 if (m_grab)
105 emit scheduledUpdateCompleted();
106 m_grab = false;
107 return doGrab;
108 }
109
setItem(QSGNode * item)110 void QSGOpenVGLayer::setItem(QSGNode *item)
111 {
112 if (item == m_item)
113 return;
114 m_item = item;
115
116 if (m_live && !m_item) {
117 delete m_offscreenSurface;
118 delete m_secondaryOffscreenSurface;
119 m_offscreenSurface = nullptr;
120 m_secondaryOffscreenSurface = nullptr;
121 }
122
123 markDirtyTexture();
124 }
125
setRect(const QRectF & rect)126 void QSGOpenVGLayer::setRect(const QRectF &rect)
127 {
128 if (rect == m_rect)
129 return;
130 m_rect = rect;
131 markDirtyTexture();
132 }
133
setSize(const QSize & size)134 void QSGOpenVGLayer::setSize(const QSize &size)
135 {
136 if (size == m_size)
137 return;
138 m_size = size;
139
140 if (m_live && m_size.isNull()) {
141 delete m_offscreenSurface;
142 delete m_secondaryOffscreenSurface;
143 m_offscreenSurface = nullptr;
144 m_secondaryOffscreenSurface = nullptr;
145 }
146
147 markDirtyTexture();
148 }
149
scheduleUpdate()150 void QSGOpenVGLayer::scheduleUpdate()
151 {
152 if (m_grab)
153 return;
154 m_grab = true;
155 if (m_dirtyTexture) {
156 emit updateRequested();
157 }
158 }
159
toImage() const160 QImage QSGOpenVGLayer::toImage() const
161 {
162 return m_offscreenSurface->readbackQImage();
163 }
164
setLive(bool live)165 void QSGOpenVGLayer::setLive(bool live)
166 {
167 if (live == m_live)
168 return;
169 m_live = live;
170
171 if (m_live && (!m_item || m_size.isNull())) {
172 delete m_offscreenSurface;
173 delete m_secondaryOffscreenSurface;
174 m_offscreenSurface = nullptr;
175 m_secondaryOffscreenSurface = nullptr;
176 }
177
178 markDirtyTexture();
179 }
180
setRecursive(bool recursive)181 void QSGOpenVGLayer::setRecursive(bool recursive)
182 {
183 m_recursive = recursive;
184 }
185
setFormat(uint format)186 void QSGOpenVGLayer::setFormat(uint format)
187 {
188 Q_UNUSED(format)
189 }
190
setHasMipmaps(bool mipmap)191 void QSGOpenVGLayer::setHasMipmaps(bool mipmap)
192 {
193 Q_UNUSED(mipmap)
194 }
195
setDevicePixelRatio(qreal ratio)196 void QSGOpenVGLayer::setDevicePixelRatio(qreal ratio)
197 {
198 m_device_pixel_ratio = ratio;
199 }
200
setMirrorHorizontal(bool mirror)201 void QSGOpenVGLayer::setMirrorHorizontal(bool mirror)
202 {
203 if (m_mirrorHorizontal == mirror)
204 return;
205 m_mirrorHorizontal = mirror;
206 markDirtyTexture();
207 }
208
setMirrorVertical(bool mirror)209 void QSGOpenVGLayer::setMirrorVertical(bool mirror)
210 {
211 if (m_mirrorVertical == mirror)
212 return;
213 m_mirrorVertical = mirror;
214 markDirtyTexture();
215 }
216
markDirtyTexture()217 void QSGOpenVGLayer::markDirtyTexture()
218 {
219 m_dirtyTexture = true;
220 if (m_live || m_grab) {
221 emit updateRequested();
222 }
223 }
224
invalidated()225 void QSGOpenVGLayer::invalidated()
226 {
227 delete m_offscreenSurface;
228 delete m_secondaryOffscreenSurface;
229 delete m_renderer;
230 m_renderer = nullptr;
231 m_offscreenSurface = nullptr;
232 m_secondaryOffscreenSurface = nullptr;
233 }
234
grab()235 void QSGOpenVGLayer::grab()
236 {
237 if (!m_item || m_size.isNull()) {
238 delete m_offscreenSurface;
239 delete m_secondaryOffscreenSurface;
240 m_offscreenSurface = nullptr;
241 m_secondaryOffscreenSurface = nullptr;
242 m_dirtyTexture = false;
243 return;
244 }
245 QSGNode *root = m_item;
246 while (root->firstChild() && root->type() != QSGNode::RootNodeType)
247 root = root->firstChild();
248 if (root->type() != QSGNode::RootNodeType)
249 return;
250
251 if (!m_renderer) {
252 m_renderer = new QSGOpenVGRenderer(m_context);
253 connect(m_renderer, SIGNAL(sceneGraphChanged()), this, SLOT(markDirtyTexture()));
254 }
255 m_renderer->setDevicePixelRatio(m_device_pixel_ratio);
256 m_renderer->setRootNode(static_cast<QSGRootNode *>(root));
257
258 bool deleteOffscreenSurfaceLater = false;
259 if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != m_size ) {
260 if (m_recursive) {
261 deleteOffscreenSurfaceLater = true;
262 delete m_secondaryOffscreenSurface;
263 m_secondaryOffscreenSurface = new QOpenVGOffscreenSurface(m_size);
264 } else {
265 delete m_offscreenSurface;
266 delete m_secondaryOffscreenSurface;
267 m_offscreenSurface = new QOpenVGOffscreenSurface(m_size);
268 m_secondaryOffscreenSurface = nullptr;
269 }
270 }
271
272 if (m_recursive && !m_secondaryOffscreenSurface)
273 m_secondaryOffscreenSurface = new QOpenVGOffscreenSurface(m_size);
274
275 // Render texture.
276 root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
277 m_renderer->nodeChanged(root, QSGNode::DirtyForceUpdate); // Force render list update.
278
279 m_dirtyTexture = false;
280
281 m_renderer->setDeviceRect(m_size);
282 m_renderer->setViewportRect(m_size);
283 QRect mirrored(m_mirrorHorizontal ? m_rect.right() * m_device_pixel_ratio : m_rect.left() * m_device_pixel_ratio,
284 m_mirrorVertical ? m_rect.top() * m_device_pixel_ratio : m_rect.bottom() * m_device_pixel_ratio,
285 m_mirrorHorizontal ? -m_rect.width() * m_device_pixel_ratio : m_rect.width() * m_device_pixel_ratio,
286 m_mirrorVertical ? m_rect.height() * m_device_pixel_ratio : -m_rect.height() * m_device_pixel_ratio);
287 m_renderer->setProjectionMatrixToRect(mirrored);
288 m_renderer->setClearColor(Qt::transparent);
289
290
291 if (m_recursive)
292 m_secondaryOffscreenSurface->makeCurrent();
293 else
294 m_offscreenSurface->makeCurrent();
295
296 m_renderer->renderScene();
297
298 // Make the previous surface and context active again
299 if (m_recursive) {
300 if (deleteOffscreenSurfaceLater) {
301 delete m_offscreenSurface;
302 m_offscreenSurface = new QOpenVGOffscreenSurface(m_size);
303 }
304 m_secondaryOffscreenSurface->doneCurrent();
305 qSwap(m_offscreenSurface, m_secondaryOffscreenSurface);
306 } else {
307 m_offscreenSurface->doneCurrent();
308 }
309
310 root->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip, opacity and render list update.
311
312 if (m_recursive)
313 markDirtyTexture(); // Continuously update if 'live' and 'recursive'.
314 }
315
comparisonKey() const316 int QSGOpenVGLayerPrivate::comparisonKey() const
317 {
318 return 0;
319 }
320
321 QT_END_NAMESPACE
322