1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qtquick3dxrglobal_p.h"
5#include "qquick3dxritem_p.h"
6#include "qquick3dxrview_p.h"
7#include <QQuickWindow>
8#include <QQuickItem>
9#include <QLoggingCategory>
10
11#include <QtQuick3DUtils/private/qssgassert_p.h>
12
13#include "qquick3dxrinputmanager_p.h"
14
15QT_BEGIN_NAMESPACE
16
17Q_DECLARE_LOGGING_CATEGORY(lcQuick3DXr);
18
19/*!
20 \qmltype XrView
21 \inherits Node
22 \inqmlmodule QtQuick3D.Xr
23 \brief Sets up the view for an Xr application.
24
25 An XrView sets up the view for an XR application.
26 The following snippet is from the \l{\qxr Simple Example} and shows
27 how to use the type.
28
29 \quotefromfile xr_simple/main.qml
30 \printto XrOrigin
31
32 \section1 Platform notes
33
34 \section2 Meta Quest Devices
35
36 To \l{XrView::passthroughEnabled}{enable passthrough} you need to add the
37 following permisson your app's \c AndroidManifest.xml file:
38
39 \badcode
40 <uses-feature android:name="com.oculus.feature.PASSTHROUGH" android:required="false"/>
41 \endcode
42
43*/
44
45QQuick3DXrView::QQuick3DXrView()
46 : m_xrRuntimeInfo(&m_xrManager)
47{
48 init();
49}
50
51QQuick3DXrView::~QQuick3DXrView()
52{
53 m_inDestructor = true;
54}
55
56/*!
57 \qmlproperty XrOrigin QtQuick3D.Xr::XrView::xrOrigin
58 \brief Holds the active XR origin.
59
60 The XR origin is the point in the scene that is considered the origin of the
61 XR coordinate system. The XR origin is used to position tracked objects like
62 the camera and controllers in the scene. An application can have multiple XrOrigins
63 but only one can be active at a time.
64
65 \note This property must be set for the scene to be rendered in XR.
66
67 \sa XrOrigin
68*/
69
70QQuick3DXrOrigin *QQuick3DXrView::xrOrigin() const
71{
72 return m_xrOrigin;
73}
74
75/*!
76 \qmlproperty SceneEnvironment QtQuick3D.Xr::XrView::environment
77 \summary Holds the SceneEnvironment for the XR view.
78*/
79
80QQuick3DSceneEnvironment *QQuick3DXrView::environment() const
81{
82 return m_xrManager.m_vrViewport ? m_xrManager.m_vrViewport->environment() : nullptr;
83}
84
85QQuick3DViewport *QQuick3DXrView::view3d() const
86{
87 return m_xrManager.m_vrViewport;
88}
89
90/*!
91 \qmlproperty bool QtQuick3D.Xr::XrView::passthroughEnabled
92 \summary Holds whether passthrough is enabled for the XR view.
93*/
94bool QQuick3DXrView::passthroughEnabled() const
95{
96 return m_xrManager.isPassthroughEnabled();
97}
98
99/*!
100 \qmlproperty QQuick3DXrRuntimeInfo QtQuick3D.Xr::XrView::runtimeInfo
101 \summary Provides information about the XR runtime for the XR view.
102*/
103
104QQuick3DXrRuntimeInfo *QQuick3DXrView::runtimeInfo() const
105{
106 return &m_xrRuntimeInfo;
107}
108
109void QQuick3DXrView::setEnvironment(QQuick3DSceneEnvironment *environment)
110{
111 QQuick3DViewport *view = m_xrManager.m_vrViewport;
112
113 // If the view is not created yet, we can't set the environment which means we need to
114 // set it again once the view is created...
115 if (!view) {
116 m_pendingSceneEnvironment = environment;
117 return;
118 }
119
120 auto oldEnvironment = view->environment();
121 if (oldEnvironment == environment)
122 return;
123
124 if (oldEnvironment)
125 disconnect(receiver: oldEnvironment);
126
127 view->setEnvironment(environment);
128
129 // The view will always have an environment, setting the environment to null will just mean the default environment
130 // is used. So querying the environment from the view is always valid (and we should do it here to make sure we're
131 // in sync with the view).
132 environment = view->environment();
133
134 handleClearColorChanged();
135 handleAAChanged();
136
137 connect(sender: environment, signal: &QQuick3DSceneEnvironment::backgroundModeChanged, context: this, slot: &QQuick3DXrView::handleClearColorChanged);
138 connect(sender: environment, signal: &QQuick3DSceneEnvironment::clearColorChanged, context: this, slot: &QQuick3DXrView::handleClearColorChanged);
139 connect(sender: environment, signal: &QQuick3DSceneEnvironment::antialiasingModeChanged, context: this, slot: &QQuick3DXrView::handleAAChanged);
140 connect(sender: environment, signal: &QQuick3DSceneEnvironment::antialiasingQualityChanged, context: this, slot: &QQuick3DXrView::handleAAChanged);
141
142 emit environmentChanged(environment);
143}
144
145/*!
146 \qmlproperty bool QtQuick3D.Xr::XrView::passthroughSupported
147 \summary Indicates whether passthrough is supported for the XR view.
148*/
149
150bool QQuick3DXrView::passthroughSupported() const
151{
152 if (!m_xrManager.isValid())
153 return false;
154
155 return m_xrManager.supportsPassthrough();
156}
157
158void QQuick3DXrView::setPassthroughEnabled(bool enable)
159{
160 if (!m_xrManager.isValid()) {
161 qWarning(msg: "Attempted to set passthrough mode without a valid XR manager");
162 return;
163 }
164
165 const bool orgPassthroughEnabled = m_xrManager.isPassthroughEnabled();
166 // bail if passthrough is not supported
167 if (!m_xrManager.setPassthroughEnabled(enable)) {
168 qWarning(msg: "Enabling Passthrough is not supported.");
169 return;
170 }
171
172 if (orgPassthroughEnabled != m_xrManager.isPassthroughEnabled())
173 emit passthroughEnabledChanged();
174}
175
176/*!
177 \qmlproperty enumeration QtQuick3D.Xr::XrView::fixedFoveation
178 \brief Controls the level of fixed foveated rendering for the XrView.
179 \default XrView.HighFoveation
180
181 Foveated rendering reduces GPU load by reducing image quality (resolution)
182 in areas where the difference is less perceptible to the eye. With fixed
183 foveated rendering, the areas with reduced visual fidelity are fixed and do
184 not change. On some platforms, there is no concept of fixed foveated
185 rendering or control over it. For example, VisionOS-based devices perform
186 dynamic, eye-tracked foveation; thus, the value of this property is
187 ignored in practice. Other devices, such as the Meta Quest 3, only
188 support fixed foveation, which makes this property relevant.
189
190 The value can be one of:
191 \value XrView.NoFoveation 0, no foveation.
192 \value XrView.LowFoveation 1, low foveation.
193 \value XrView.MediumFoveation 2, medium foveation.
194 \value XrView.HighFoveation 3, high foveation.
195
196 Where supported, the default is \c HighFoveation. Therefore, changing this
197 value in applications should be rarely needed in practice.
198*/
199
200QQuick3DXrView::FoveationLevel QQuick3DXrView::fixedFoveation() const
201{
202 return FoveationLevel(m_xrManager.getFixedFoveationLevel());
203}
204
205void QQuick3DXrView::setFixedFoveation(FoveationLevel level)
206{
207 const auto orgFoviationLevel = m_xrManager.getFixedFoveationLevel();
208 m_xrManager.setFixedFoveationLevel(QtQuick3DXr::FoveationLevel(level));
209 if (orgFoviationLevel != m_xrManager.getFixedFoveationLevel())
210 emit fixedFoveationChanged();
211}
212
213/*!
214 \qmlproperty bool QtQuick3D.Xr::XrView::isQuitOnSessionEndEnabled
215 \brief Holds whether the application should quit when the XR session ends.
216*/
217
218bool QQuick3DXrView::isQuitOnSessionEndEnabled() const
219{
220 return m_quitOnSessionEnd;
221}
222
223void QQuick3DXrView::setQuitOnSessionEnd(bool enable)
224{
225 if (m_quitOnSessionEnd == enable)
226 return;
227
228 m_quitOnSessionEnd = enable;
229 emit quitOnSessionEndChanged();
230}
231/*!
232 \qmlproperty RenderStats QtQuick3D.Xr::XrView::renderStats
233 \summary Holds rendering statistics for the XR view.
234*/
235
236QQuick3DRenderStats *QQuick3DXrView::renderStats() const
237{
238 return m_xrManager.m_vrViewport ? m_xrManager.m_vrViewport->renderStats() : nullptr;
239}
240
241void QQuick3DXrView::updateViewportGeometry()
242{
243 auto contentItem = m_xrManager.m_quickWindow->contentItem();
244 auto viewport = m_xrManager.m_vrViewport;
245 if (viewport->height() != contentItem->height())
246 viewport->setHeight(contentItem->height());
247 if (viewport->width() != contentItem->width())
248 viewport->setWidth(contentItem->width());
249 if (viewport->x() != contentItem->x())
250 viewport->setX(contentItem->x());
251 if (viewport->y() != contentItem->y())
252 viewport->setY(contentItem->y());
253}
254
255void QQuick3DXrView::handleSessionEnded()
256{
257 emit sessionEnded();
258 if (m_quitOnSessionEnd)
259 QCoreApplication::quit();
260}
261
262void QQuick3DXrView::handleClearColorChanged()
263{
264 auto env = environment();
265
266 if (env) {
267 if (env->backgroundMode() == QQuick3DSceneEnvironment::Color)
268 m_xrManager.m_quickWindow->setColor(env->clearColor());
269 else if (env->backgroundMode() == QQuick3DSceneEnvironment::Transparent)
270 m_xrManager.m_quickWindow->setColor(Qt::transparent);
271 }
272}
273
274void QQuick3DXrView::handleAAChanged()
275{
276 auto env = environment();
277 int samples = 1;
278 if (env && env->antialiasingMode() == QQuick3DSceneEnvironment::MSAA) {
279 switch (env->antialiasingQuality()) {
280 case QQuick3DSceneEnvironment::Medium:
281 samples = 2;
282 break;
283 case QQuick3DSceneEnvironment::High:
284 samples = 4;
285 break;
286 case QQuick3DSceneEnvironment::VeryHigh:
287 samples = 8;
288 break;
289 }
290 }
291 m_xrManager.setSamples(samples);
292}
293
294bool QQuick3DXrView::init()
295{
296 if (m_isInitialized) {
297 qWarning(msg: "Already initialized!");
298 return false;
299 }
300
301 connect(sender: &m_xrManager, signal: &QQuick3DXrManager::sessionEnded, context: this, slot: &QQuick3DXrView::handleSessionEnded);
302 connect(sender: &m_xrManager, signal: &QQuick3DXrManager::frameReady, context: this, slot: &QQuick3DXrView::frameReady);
303 connect(sender: &m_xrManager, signal: &QQuick3DXrManager::referenceSpaceChanged, context: this, slot: &QQuick3DXrView::referenceSpaceChanged);
304 connect(sender: &m_xrManager, signal: &QQuick3DXrManager::multiViewRenderingEnabledChanged, context: this, slot: &QQuick3DXrView::multiViewRenderingEnabledChanged);
305 connect(sender: &m_xrManager, signal: &QQuick3DXrManager::initialized, context: this, slot: &QQuick3DXrView::init, type: Qt::UniqueConnection);
306
307 if (!m_xrManager.isReady() && !m_xrManager.initialize()) {
308 qCDebug(lcQuick3DXr, "Waiting for XR platform to be initialized");
309
310 return false;
311 }
312
313 if (!m_xrManager.initialize()) {
314 QString errorString = m_xrManager.errorString();
315 if (errorString.isEmpty())
316 errorString = tr(s: "Failed to initialize XR platform");
317 qWarning(msg: "\n%s\n", qPrintable(errorString));
318 QMetaObject::invokeMethod(obj: this, member: "initializeFailed", c: Qt::QueuedConnection, arguments&: errorString);
319 return false;
320 }
321
322 // Create View3D
323 QSSG_CHECK_X(m_xrManager.m_vrViewport == nullptr, "View3D already created!");
324 auto viewport = new QQuick3DViewport(QQuick3DViewport::PrivateInstanceType::XrViewInstance);
325 viewport->setRenderMode(QQuick3DViewport::Underlay);
326 auto contentItem = m_xrManager.m_quickWindow->contentItem();
327 viewport->setParentItem(contentItem);
328 m_xrManager.m_vrViewport = viewport;
329 viewport->setImportScene(this);
330
331 contentItem->forceActiveFocus(reason: Qt::MouseFocusReason);
332
333 connect(sender: contentItem, signal: &QQuickItem::heightChanged, context: this, slot: &QQuick3DXrView::updateViewportGeometry);
334 connect(sender: contentItem, signal: &QQuickItem::widthChanged, context: this, slot: &QQuick3DXrView::updateViewportGeometry);
335 connect(sender: contentItem, signal: &QQuickItem::xChanged, context: this, slot: &QQuick3DXrView::updateViewportGeometry);
336 connect(sender: contentItem, signal: &QQuickItem::yChanged, context: this, slot: &QQuick3DXrView::updateViewportGeometry);
337
338 QQuick3DSceneEnvironment *env = environment();
339 if (env) {
340 connect(sender: env, signal: &QQuick3DSceneEnvironment::backgroundModeChanged, context: this, slot: &QQuick3DXrView::handleClearColorChanged);
341 connect(sender: env, signal: &QQuick3DSceneEnvironment::clearColorChanged, context: this, slot: &QQuick3DXrView::handleClearColorChanged);
342 connect(sender: env, signal: &QQuick3DSceneEnvironment::antialiasingModeChanged, context: this, slot: &QQuick3DXrView::handleAAChanged);
343 connect(sender: env, signal: &QQuick3DSceneEnvironment::antialiasingQualityChanged, context: this, slot: &QQuick3DXrView::handleAAChanged);
344 }
345
346 // NOTE: If we've called async, we need to make sure the environment, etc. is set again
347 setEnvironment(m_pendingSceneEnvironment);
348 m_pendingSceneEnvironment = nullptr;
349
350 m_xrManager.update();
351
352 m_isInitialized = true;
353
354 return m_isInitialized;
355}
356
357/*!
358 \qmlmethod pickResult XrView::rayPick(vector3d origin, vector3d direction)
359
360 This method will \e shoot a ray into the scene starting at \a origin and in
361 \a direction and return information about the nearest intersection with an
362 object in the scene.
363
364 For example, pass the position and forward vector of
365 any object in a scene to see what object is in front of an item. This
366 makes it possible to do picking from any point in the scene.
367 */
368QQuick3DPickResult QQuick3DXrView::rayPick(const QVector3D &origin, const QVector3D &direction) const
369{
370 return m_xrManager.m_vrViewport->rayPick(origin, direction);
371}
372
373/*!
374 \qmlmethod List<pickResult> XrView::rayPickAll(vector3d origin, vector3d direction)
375
376 This method will \e shoot a ray into the scene starting at \a origin and in
377 \a direction and return a list of information about the nearest intersections with
378 objects in the scene.
379 The list is presorted by distance from the origin along the direction
380 vector with the nearest intersections appearing first and the furthest
381 appearing last.
382
383 This can, for instance, be called with the position and forward vector of
384 any object in a scene to see what objects are in front of an item. This
385 makes it possible to do picking from any point in the scene.
386 */
387QList<QQuick3DPickResult> QQuick3DXrView::rayPickAll(const QVector3D &origin, const QVector3D &direction) const
388{
389 return m_xrManager.m_vrViewport->rayPickAll(origin, direction);
390}
391
392/*!
393 \qmlmethod XrView::setTouchpoint(Item target, point position, int pointId, bool pressed)
394
395 Sends a synthetic touch event to \a target, moving the touch point with ID \a pointId to \a position,
396 with \a pressed determining if the point is pressed.
397 Also sends the appropriate touch release event if \a pointId was previously active on a different
398 item.
399*/
400
401void QQuick3DXrView::setTouchpoint(QQuickItem *target, const QPointF &position, int pointId, bool pressed)
402{
403 view3d()->setTouchpoint(target, position, pointId, active: pressed);
404}
405
406// TODO: Maybe do a proper QQuick3DXrViewPrivate instead
407struct QQuick3DXrView::XrTouchState
408{
409 QHash<int, QQuick3DXrItem::TouchState> points;
410};
411
412/*!
413 \qmlmethod vector3d XrView::processTouch(vector3d position, int pointId)
414
415 This method will search for an XrItem near \a position and send a virtual
416 touch event with touch point ID \a pointId if \a position maps to a point
417 on the surface.
418
419 The return value is the offset between \a position and the touched point on
420 the surface. This can be used to prevent a hand model from passing through
421 an XrItem.
422
423 \sa XrHandModel
424
425*/
426
427QVector3D QQuick3DXrView::processTouch(const QVector3D &pos, int pointId)
428{
429 QVector3D offset;
430 if (m_xrItems.isEmpty())
431 return offset;
432
433 if (!m_touchState)
434 m_touchState = new XrTouchState;
435 QQuick3DXrItem::TouchState &state = m_touchState->points[pointId];
436 state.pointId = pointId; // in case it's a new point that was default-constructed
437
438 auto *prevTarget = state.target;
439 bool grabbed = false;
440 if (prevTarget) {
441 grabbed = prevTarget->handleVirtualTouch(view: this, pos, touchState: &state, offset: &offset);
442 }
443 for (auto *item : std::as_const(t&: m_xrItems)) {
444 if (grabbed)
445 break;
446 if (item != prevTarget)
447 grabbed = item->handleVirtualTouch(view: this, pos, touchState: &state, offset: &offset);
448 }
449
450 return offset;
451}
452
453/*!
454 \qmlmethod object XrView::touchpointState(int pointId)
455
456 This method returns the state of the touch point with ID \a pointId.
457 The state is represented by a map from property names to values:
458
459 \table
460 \header
461 \li Key
462 \li Type
463 \li Description
464 \row
465 \li \c grabbed
466 \li \c bool
467 \li Is the point grabbed by an item? If \c false, all other values are \c undefined.
468 \row
469 \li \c target
470 \li XrItem
471 \li The item that is grabbing the touch point.
472 \row
473 \li \c pressed
474 \li \c bool
475 \li Is the touch point pressed?
476 \row
477 \li \c cursorPos
478 \li \c point
479 \li The 2D position of the touch point within \c target
480 \row
481 \li \c touchDistance
482 \li \c real
483 \li The distance from the plane to the touch point. It will be \c 0 if \c pressed is \c true.
484 \endtable
485
486 */
487
488#define Q_TOUCHPOINT_STATE(prop) { QStringLiteral(#prop), QVariant::fromValue(it->prop) }
489QVariantMap QQuick3DXrView::touchpointState(int pointId) const
490{
491 auto constexpr end = QHash<int, QQuick3DXrItem::TouchState>::const_iterator();
492 auto it = m_touchState ? m_touchState->points.constFind(key: pointId) : end;
493
494 if (it == end)
495 return { { QStringLiteral("grabbed"), QVariant::fromValue(value: false) } };
496
497 return { Q_TOUCHPOINT_STATE(target),
498 Q_TOUCHPOINT_STATE(grabbed),
499 Q_TOUCHPOINT_STATE(pressed),
500 Q_TOUCHPOINT_STATE(cursorPos),
501 Q_TOUCHPOINT_STATE(touchDistance) };
502}
503#undef Q_TOUCHPOINT_STATE
504
505/*!
506 \qmlproperty enumeration QtQuick3D.Xr::XrView::referenceSpace
507 \brief Gets or sets the reference space for the XR view.
508
509 It can be one of:
510 \value XrView.ReferenceSpaceUnknown
511 \value XrView.ReferenceSpaceLocal Origin is at the default view position (typically defined by a "reset view" operation).
512 \value XrView.ReferenceSpaceStage Origin is at floor height in the center of the user's defined area.
513 \value XrView.ReferenceSpaceLocalFloor Origin is at floor height, below the default view position.
514
515 \c ReferenceSpaceLocal is mainly useful for seated applications where the content is not positioned
516 relative to the floor, for example floating menus. The content will move when the user resets the view.
517
518 \c ReferenceSpaceStage is mainly useful for room-scale applications where the user will move freely within the
519 playing area. The content will not move when the user resets the view.
520
521 \c ReferenceSpaceLocalFloor is mainly useful for stationary applications (seated or standing) where the content is
522 positioned relative to the floor. The content will move when the user resets the view.
523
524 \default XrView.ReferenceSpaceLocal
525*/
526
527QQuick3DXrView::ReferenceSpace QQuick3DXrView::referenceSpace() const
528{
529 return ReferenceSpace(m_xrManager.getReferenceSpace());
530}
531
532void QQuick3DXrView::setReferenceSpace(ReferenceSpace newReferenceSpace)
533{
534 m_xrManager.setReferenceSpace(QtQuick3DXr::ReferenceSpace(newReferenceSpace));
535}
536
537bool QQuick3DXrView::depthSubmissionEnabled() const
538{
539 if (!m_xrManager.isValid()) {
540 qWarning(msg: "Attempted to check depth submission mode without a valid XR manager");
541 return false;
542 }
543
544 return m_xrManager.isDepthSubmissionEnabled();
545}
546
547/*!
548 \qmlproperty bool QtQuick3D.Xr::XrView::multiViewRenderingSupported
549
550 \brief This read-only property reports the availability of \l{Multiview Rendering}.
551
552 \sa multiViewRenderingEnabled
553 */
554bool QQuick3DXrView::isMultiViewRenderingSupported() const
555{
556 if (!m_xrManager.isValid())
557 return false;
558
559 return m_xrManager.isMultiViewRenderingSupported();
560}
561
562/*!
563 \qmlproperty bool QtQuick3D.Xr::XrView::multiViewRenderingEnabled
564
565 \brief This is a read-only property that reports if \l{Multiview Rendering} is enabled for the XR view.
566
567 \default true
568
569 This property tells you if multiview rendering is actually in use at run time.
570 When not supported, the value will flip back to \c false.
571
572 Enabling multiview rendering is recommended. It can improve performance and reduce
573 CPU and GPU power usage. It defaults to disabled to ensure maximum
574 compatibility. Developers are encouraged to verify that their application
575 renders as expected with multiViewRenderingEnabled set to \c true and then
576 leave it set afterward.
577
578 \note Certain Qt Quick and Quick 3D features that involve shader code that is
579 provided by the application may need this code to be modified to be multiview
580 compatible. Examples of these are custom 2D and 3D materials and
581 postprocessing effects. The \l {Multiview Rendering} documentation provides
582 more information on this and how to disable multiview rendering.
583
584 \sa multiViewRenderingSupported {Multiview Rendering}
585*/
586bool QQuick3DXrView::multiViewRenderingEnabled() const
587{
588 if (!m_xrManager.isValid())
589 return false;
590
591 return m_xrManager.isMultiViewRenderingEnabled();
592}
593
594void QQuick3DXrView::registerXrItem(QQuick3DXrItem *newXrItem)
595{
596 m_xrItems.append(t: newXrItem);
597}
598
599void QQuick3DXrView::unregisterXrItem(QQuick3DXrItem *xrItem)
600{
601 m_xrItems.removeAll(t: xrItem);
602}
603
604/*!
605 \qmlproperty bool QtQuick3D.Xr::XrView::depthSubmissionEnabled
606 \brief Controls whether submitting the depth buffer to the XR compositor
607 is enabled.
608 \default false
609
610 By default, the depth buffer used by the 3D scene in the XrView is not exposed
611 to the XR compositor. However, in some platforms, depth submission is implicit
612 and cannot be disabled or controlled by the application. An example of this is
613 VisionOS. Changing this property has no effect on those platforms. Elsewhere,
614 with OpenXR in particular, support depends on the OpenXR implementation used
615 at run time.
616
617 It is always safe to set depthSubmissionEnabled to \c true. It will just have
618 no effect when not supported by the underlying stack. To be sure, you can
619 inspect the debug output to see if depth submission is in use.
620 Submitting the depth buffer may improve reprojections that the XR compositor
621 may perform. Reprojection could happen, for example, when the system cannot
622 maintain the target frame rate and thus has to resort to predicting frame
623 contents to improve and stabilize the user's perception of the
624 scene and reduce possible motion sickness. However, the application and
625 Qt have no control over data usage. It could also happen that
626 submitting depth data has no practical effects and is ignored by the
627 underlying XR runtime and compositor.
628
629 In practice, submitting the depth buffer implies rendering into a depth
630 texture provided by the XR runtime instead of the intermediate texture/render buffer
631 created and managed by Qt. Rendering into a depth texture has certain lower-level
632 consequences that can have a performance impact:
633
634 When using \l{QtQuick3D::SceneEnvironment::antialiasingMode}{multisample antialiasing}
635 (MSAA), enabling depth submission implies rendering into a multisample depth
636 texture and resolving the samples into the non-multisample depth texture provided by
637 the XR runtime. Without depth submission,
638 the resolve step would not be necessary. In addition, some 3D APIs
639 do not support resolving multisample depth-stencil data (see
640 the \l{QRhi::ResolveDepthStencil} flag for details). Without this support,
641 attempts to enable depth submission in combination with MSAA are gracefully ignored.
642
643 Even when MSAA is not used, enabling depth submission triggers writing out
644 depth data with 3D APIs that have control over this. The store operation for
645 depth/stencil data is typically indicated by Qt as unnecessary, which can
646 have positive performance impacts on tiled GPU architectures. This is not
647 done with depth submission because depth data must always be written out
648 from Qt's perspective.
649
650 \note We recommended that developers test their applications with depth
651 submission enabled, evaluate the advantages and disadvantages, and make a
652 conscious choice based on their testing if they wish to enable it or not.
653*/
654
655void QQuick3DXrView::setDepthSubmissionEnabled(bool enable)
656{
657 if (!m_xrManager.isValid()) {
658 qWarning(msg: "Attempted to set depth submission mode without a valid XR manager");
659 return;
660 }
661
662 const bool orgDepthSubmission = m_xrManager.isDepthSubmissionEnabled();
663
664 m_xrManager.setDepthSubmissionEnabled(enable);
665
666 if (orgDepthSubmission != m_xrManager.isDepthSubmissionEnabled())
667 emit depthSubmissionEnabledChanged();
668}
669
670void QQuick3DXrView::setXROrigin(QQuick3DXrOrigin *newXrOrigin)
671{
672 if (m_xrOrigin == newXrOrigin)
673 return;
674
675 QQuick3DObjectPrivate::attachWatcher(context: this, setter: &QQuick3DXrView::setXROrigin, newO: newXrOrigin, oldO: m_xrOrigin);
676
677 m_xrOrigin = newXrOrigin;
678
679 // Make sure the XrOrigin has a parent item, if it hasn't, we're it.
680 if (m_xrOrigin && !m_xrOrigin->parentItem())
681 m_xrOrigin->setParentItem(this);
682
683 m_xrManager.setXROrigin(m_xrOrigin);
684
685 emit xrOriginChanged();
686}
687
688QQuick3DViewport *QQuick3DXrViewPrivate::getView3d(QQuick3DXrView *view)
689{
690 QSSG_ASSERT(view != nullptr, return nullptr);
691 return view->view3d();
692}
693
694/*!
695 \qmlsignal XrView::initializeFailed(const QString &errorString)
696
697 Emitted when initialization fails, and there is a new \a errorString
698 describing the failure.
699 */
700
701/*!
702 \qmlsignal XrView::sessionEnded()
703
704 Emitted when the session ends.
705 */
706
707/*!
708 \qmlsignal XrView::frameReady()
709 \internal
710
711 Emitted when a new frame is ready.
712 */
713
714QT_END_NAMESPACE
715

source code of qtquick3d/src/xr/quick3dxr/qquick3dxrview.cpp