1/****************************************************************************
2**
3** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D 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 "qrendersurfaceselector.h"
41#include "qrendersurfaceselector_p.h"
42
43#include <QtGui/QWindow>
44#include <QtGui/QScreen>
45#include <QtGui/QOffscreenSurface>
46#include <Qt3DCore/qentity.h>
47#include <Qt3DRender/qrendersettings.h>
48#include <Qt3DRender/qframegraphnodecreatedchange.h>
49
50QT_BEGIN_NAMESPACE
51
52namespace Qt3DRender {
53
54/*!
55 \class Qt3DRender::QRenderSurfaceSelector
56 \inmodule Qt3DRender
57 \brief Provides a way of specifying the render surface.
58 \since 5.7
59
60 The Qt3DRender::QRenderSurfaceSelector can be used to select the surface, where
61 Qt3D renders the content. The surface can either be window surface or offscreen
62 surface. The externalRenderTargetSize is used to specify the actual size of the
63 surface when offscreen surface is used.
64
65 When DPI scaling is used by the system, the logical surface size, which is used
66 by mouse events, and the actual 'physical' size of the surface can differ.
67 The surfacePixelRatio is the factor to convert the logical size to the physical
68 size.
69
70 \sa QWindow, QOffscreenSurface, QSurface
71 */
72
73/*!
74 \qmltype RenderSurfaceSelector
75 \inqmlmodule Qt3D.Render
76 \since 5.7
77 \instantiates Qt3DRender::QRenderSurfaceSelector
78 \inherits FrameGraphNode
79 \brief Provides a way of specifying the render surface.
80
81 The RenderSurfaceSelector can be used to select the surface, where
82 Qt3D renders the content. The surface can either be window surface or offscreen
83 surface. The externalRenderTargetSize is used to specify the actual size of the
84 render target when offscreen surface is used.
85
86 When DPI scaling is used by the system, the logical surface size, which is used
87 by mouse events, and the actual 'physical' size of the surface can differ.
88 The surfacePixelRatio is the factor to convert the logical size to the physical
89 size.
90 */
91
92/*! \qmlproperty QSurface Qt3D.Render::RenderSurfaceSelector::surface
93 Holds the surface.
94 */
95
96/*! \qmlproperty size Qt3D.Render::RenderSurfaceSelector::externalRenderTargetSize
97
98 Holds the size of the external render target.
99 */
100
101/*! \qmlproperty real Qt3D.Render::RenderSurfaceSelector::surfacePixelRatio
102
103 Holds the surfacePixelRatio of the surface.
104 */
105
106/*!
107 \property QRenderSurfaceSelector::surface
108 Holds the surface
109 */
110
111/*!
112 \property QRenderSurfaceSelector::externalRenderTargetSize
113 Holds the size of the external render target.
114 */
115
116/*! \property QRenderSurfaceSelector::surfacePixelRatio
117
118 Holds the surfacePixelRatio of the surface.
119 */
120
121QRenderSurfaceSelectorPrivate::QRenderSurfaceSelectorPrivate()
122 : Qt3DRender::QFrameGraphNodePrivate()
123 , m_surface(nullptr)
124 , m_surfaceEventFilter(new Qt3DRender::Render::PlatformSurfaceFilter())
125 , m_surfacePixelRatio(1.0f)
126{
127}
128
129QRenderSurfaceSelectorPrivate::~QRenderSurfaceSelectorPrivate()
130{
131 QObject::disconnect(m_heightConn);
132 QObject::disconnect(m_widthConn);
133 QObject::disconnect(m_screenConn);
134}
135
136QRenderSurfaceSelector *QRenderSurfaceSelectorPrivate::find(QObject *rootObject)
137{
138 QFrameGraphNode *frameGraphRoot = qobject_cast<QFrameGraphNode *>(object: rootObject);
139
140 if (!frameGraphRoot) {
141 auto rendererSettings = rootObject->findChild<Qt3DRender::QRenderSettings *>();
142 if (!rendererSettings) {
143 qWarning() << "No renderer settings component found";
144 return nullptr;
145 }
146
147 frameGraphRoot = rendererSettings->activeFrameGraph();
148 if (!frameGraphRoot) {
149 qWarning() << "No active frame graph found";
150 return nullptr;
151 }
152 }
153
154 auto surfaceSelector = qobject_cast<Qt3DRender::QRenderSurfaceSelector *>(object: frameGraphRoot);
155 if (!surfaceSelector)
156 surfaceSelector = frameGraphRoot->findChild<Qt3DRender::QRenderSurfaceSelector *>();
157
158 if (!surfaceSelector)
159 qWarning() << "No render surface selector found in frame graph";
160
161 return surfaceSelector;
162}
163
164void QRenderSurfaceSelectorPrivate::setExternalRenderTargetSize(const QSize &size)
165{
166 m_externalRenderTargetSize = size;
167}
168
169/*!
170 Constructs QRenderSurfaceSelector with given \a parent.
171 */
172QRenderSurfaceSelector::QRenderSurfaceSelector(Qt3DCore::QNode *parent)
173 : Qt3DRender::QFrameGraphNode(*new QRenderSurfaceSelectorPrivate, parent)
174{
175}
176
177/*!
178 \internal
179 */
180QRenderSurfaceSelector::~QRenderSurfaceSelector()
181{
182}
183
184/*!
185 \internal
186 */
187QRenderSurfaceSelector::QRenderSurfaceSelector(QRenderSurfaceSelectorPrivate &dd, Qt3DCore::QNode *parent)
188 : Qt3DRender::QFrameGraphNode(dd, parent)
189{
190}
191
192QObject *QRenderSurfaceSelector::surface() const
193{
194 Q_D(const QRenderSurfaceSelector);
195 QObject *surfaceObj = nullptr;
196 if (!d->m_surface)
197 return surfaceObj;
198
199 switch (d->m_surface->surfaceClass()) {
200 case QSurface::Window:
201 surfaceObj = static_cast<QWindow *>(d->m_surface);
202 break;
203
204 case QSurface::Offscreen:
205 surfaceObj = static_cast<QOffscreenSurface *>(d->m_surface);
206 break;
207 }
208
209 return surfaceObj;
210}
211
212/*!
213 Sets \a surfaceObject.
214 */
215void QRenderSurfaceSelector::setSurface(QObject *surfaceObject)
216{
217 Q_D(QRenderSurfaceSelector);
218 QSurface *surface = nullptr;
219 if (surfaceObject) {
220 QWindow *window = qobject_cast<QWindow *>(o: surfaceObject);
221 if (window) {
222 surface = static_cast<QSurface *>(window);
223 } else {
224 QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(object: surfaceObject);
225 if (offscreen)
226 surface = static_cast<QSurface *>(offscreen);
227 }
228
229 Q_ASSERT_X(surface, Q_FUNC_INFO, "surfaceObject is not a valid QSurface object");
230 }
231
232 if (d->m_surface == surface)
233 return;
234
235 if (d->m_surface && d->m_surface->surfaceClass() == QSurface::Window) {
236 QWindow *prevWindow = static_cast<QWindow *>(d->m_surface);
237 if (prevWindow) {
238 QObject::disconnect(d->m_widthConn);
239 QObject::disconnect(d->m_heightConn);
240 QObject::disconnect(d->m_screenConn);
241 }
242 }
243 d->m_surface = surface;
244
245 // The platform surface filter only deals with QObject
246 // We assume therefore that our surface is actually a QObject underneath
247 if (d->m_surface) {
248 switch (d->m_surface->surfaceClass()) {
249 case QSurface::Window: {
250 QWindow *window = static_cast<QWindow *>(d->m_surface);
251 d->m_surfaceEventFilter->setSurface(window);
252
253 if (window) {
254 d->m_widthConn = QObject::connect(sender: window, signal: &QWindow::widthChanged, slot: [=] (int) {
255 d->update();
256 });
257 d->m_heightConn = QObject::connect(sender: window, signal: &QWindow::heightChanged, slot: [=] (int) {
258 d->update();
259 });
260 d->m_screenConn = QObject::connect(sender: window, signal: &QWindow::screenChanged, slot: [=] (QScreen *screen) {
261 if (screen && !qFuzzyCompare(p1: surfacePixelRatio(), p2: float(screen->devicePixelRatio())))
262 setSurfacePixelRatio(float(screen->devicePixelRatio()));
263 });
264 setSurfacePixelRatio(float(window->devicePixelRatio()));
265 }
266
267 break;
268 }
269 case QSurface::Offscreen: {
270 d->m_surfaceEventFilter->setSurface(static_cast<QOffscreenSurface *>(d->m_surface));
271 break;
272 }
273
274 default:
275 Q_UNREACHABLE();
276 break;
277 }
278 } else {
279 QWindow *nullWindow = nullptr;
280 d->m_surfaceEventFilter->setSurface(nullWindow);
281 }
282 emit surfaceChanged(surface: surfaceObject);
283}
284
285QSize QRenderSurfaceSelector::externalRenderTargetSize() const
286{
287 Q_D(const QRenderSurfaceSelector);
288 return d->externalRenderTargetSize();
289}
290
291void QRenderSurfaceSelector::setSurfacePixelRatio(float ratio)
292{
293 Q_D(QRenderSurfaceSelector);
294 if (qFuzzyCompare(p1: d->m_surfacePixelRatio, p2: ratio))
295 return;
296 d->m_surfacePixelRatio = ratio;
297 emit surfacePixelRatioChanged(ratio);
298}
299
300float QRenderSurfaceSelector::surfacePixelRatio() const
301{
302 Q_D(const QRenderSurfaceSelector);
303 return d->m_surfacePixelRatio;
304}
305/*!
306 Sets render target \a size if different than underlying surface size.
307 Tells picking the correct size.
308 */
309void QRenderSurfaceSelector::setExternalRenderTargetSize(const QSize &size)
310{
311 Q_D(QRenderSurfaceSelector);
312 if (size != d->m_externalRenderTargetSize) {
313 d->setExternalRenderTargetSize(size);
314 emit externalRenderTargetSizeChanged(size);
315 }
316}
317
318Qt3DCore::QNodeCreatedChangeBasePtr QRenderSurfaceSelector::createNodeCreationChange() const
319{
320 auto creationChange = QFrameGraphNodeCreatedChangePtr<QRenderSurfaceSelectorData>::create(arguments: this);
321 auto &data = creationChange->data;
322 Q_D(const QRenderSurfaceSelector);
323 data.surface = QPointer<QObject>(surface());
324 data.externalRenderTargetSize = d->m_externalRenderTargetSize;
325 data.surfacePixelRatio = d->m_surfacePixelRatio;
326 return creationChange;
327}
328
329} // namespace Qt3DRender
330
331QT_END_NAMESPACE
332

source code of qt3d/src/render/framegraph/qrendersurfaceselector.cpp