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

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