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