Revision control
Copy as Markdown
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
// Qt-Security score:significant reason:default
#include "qquick3dxrmanager_p.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QDebug>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
#include <rhi/qrhi.h>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/QQuickRenderControl>
#include <QtQuick/QQuickRenderTarget>
#include <QtQuick/QQuickItem>
#include <QtQuick3D/private/qquick3dnode_p.h>
#include <QtQuick3D/private/qquick3dviewport_p.h>
// #include "qquick3dxrcamera_p.h"
#include "qquick3dxranimationdriver_p.h"
#if defined(Q_OS_VISIONOS)
# include <QtQuick3DXr/private/qquick3dxrmanager_visionos_p.h>
#else
# include "openxr/qquick3dxrmanager_openxr_p.h"
#endif
#include "qquick3dxrorigin_p.h"
#include "qquick3dxrinputmanager_p.h"
QT_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQuick3DXr);
Q_LOGGING_CATEGORY(lcQuick3DXr, "qt.quick3d.xr");
QQuick3DXrManager::QQuick3DXrManager(QObject *parent)
: QObject(parent)
, d_ptr(new QQuick3DXrManagerPrivate(*this))
{
}
QQuick3DXrManager::~QQuick3DXrManager()
{
teardown();
// maintain the correct order
delete m_vrViewport;
delete m_quickWindow;
delete m_renderControl;
delete m_animationDriver;
}
bool QQuick3DXrManager::isReady() const
{
Q_D(const QQuick3DXrManager);
return d->isReady();
}
bool QQuick3DXrManager::initialize()
{
Q_D(QQuick3DXrManager);
QString m_errorString;
// TODO: Handle visionos being async a bit better
if (!d->initialize()) {
if (!d->isReady())
m_errorString = QStringLiteral("Waiting for the renderer to start.");
else
m_errorString = QStringLiteral("Failed to initialize the XR manager.");
return false;
}
// Setup Graphics
return setupGraphics();
}
void QQuick3DXrManager::teardown()
{
Q_D(QQuick3DXrManager);
d->teardown();
}
bool QQuick3DXrManager::isValid() const
{
Q_D(const QQuick3DXrManager);
return d->isValid();
}
bool QQuick3DXrManager::setPassthroughEnabled(bool enabled)
{
Q_D(QQuick3DXrManager);
// Returns true if passthrough is supported
return d->setPassthroughEnabled(enabled);
}
bool QQuick3DXrManager::isPassthroughEnabled() const
{
Q_D(const QQuick3DXrManager);
return d->isPassthroughEnabled();
}
void QQuick3DXrManager::setMultiViewRenderingEnabled(bool enable)
{
Q_D(QQuick3DXrManager);
d->setMultiViewRenderingEnabled(enable);
}
bool QQuick3DXrManager::isMultiViewRenderingEnabled() const
{
Q_D(const QQuick3DXrManager);
return d->isMultiViewRenderingEnabled();
}
bool QQuick3DXrManager::isMultiViewRenderingSupported() const
{
QRhi *rhi = m_renderControl->rhi();
return rhi ? rhi->isFeatureSupported(QRhi::MultiView) : false;
}
void QQuick3DXrManager::setXROrigin(QQuick3DXrOrigin *origin)
{
m_xrOrigin = origin;
update();
}
void QQuick3DXrManager::getDefaultClipDistances(float &nearClip, float &farClip) const
{
Q_D(const QQuick3DXrManager);
d->getDefaultClipDistances(nearClip, farClip);
}
QtQuick3DXr::FoveationLevel QQuick3DXrManager::getFixedFoveationLevel() const
{
#if defined(Q_OS_VISIONOS)
// Foveation is not configurable on VisionOS
return QtQuick3DXr::FoveationLevel::HighFoveation;
#else
Q_D(const QQuick3DXrManager);
return QtQuick3DXr::FoveationLevel(d->m_foveationLevel);
#endif
}
void QQuick3DXrManager::setFixedFoveationLevel(QtQuick3DXr::FoveationLevel level)
{
#if defined(Q_OS_VISIONOS)
// Foveation is not configurable on VisionOS
Q_UNUSED(level);
#else
Q_D(QQuick3DXrManager);
const XrFoveationLevelFB xrLevel = XrFoveationLevelFB(level);
if (d->m_foveationLevel == xrLevel)
return;
d->m_foveationLevel = xrLevel;
d->setupMetaQuestFoveation();
#endif
}
QtQuick3DXr::ReferenceSpace QQuick3DXrManager::getReferenceSpace() const
{
Q_D(const QQuick3DXrManager);
return d->getReferenceSpace();
}
void QQuick3DXrManager::setReferenceSpace(QtQuick3DXr::ReferenceSpace newReferenceSpace)
{
Q_D(QQuick3DXrManager);
d->setReferenceSpace(newReferenceSpace);
}
bool QQuick3DXrManager::isDepthSubmissionEnabled() const
{
Q_D(const QQuick3DXrManager);
return d->isDepthSubmissionEnabled();
}
void QQuick3DXrManager::setDepthSubmissionEnabled(bool enable)
{
Q_D(QQuick3DXrManager);
d->setDepthSubmissionEnabled(enable);
}
QString QQuick3DXrManager::errorString() const
{
Q_D(const QQuick3DXrManager);
return d->errorString();
}
void QQuick3DXrManager::setSamples(int samples)
{
Q_D(QQuick3DXrManager);
d->setSamples(samples);
}
void QQuick3DXrManager::update()
{
Q_D(QQuick3DXrManager);
d->update();
}
bool QQuick3DXrManager::event(QEvent *e)
{
Q_D(QQuick3DXrManager);
if (e->type() == QEvent::UpdateRequest) {
d->processXrEvents();
d->update();
return true;
}
return QObject::event(e);
}
bool QQuick3DXrManager::isMultiviewRenderingDisabled()
{
const bool disabled = qEnvironmentVariableIntValue("QT_QUICK3D_XR_DISABLE_MULTIVIEW") != 0;
return disabled;
}
QQuick3DXrInputManager *QQuick3DXrManager::getInputManager() const
{
Q_D(const QQuick3DXrManager);
return d->m_inputManager.data();
}
bool QQuick3DXrManager::setupGraphics()
{
Q_D(QQuick3DXrManager);
// FIXME: Should probably make sure we don't accidentally get here more then once
// or if we're re-initializing, in which case: make sure to clean up properly first.
if (d->isGraphicsInitialized())
return true;
preSetupQuickScene();
if (!d->setupGraphics(m_quickWindow))
return false;
if (!setupQuickScene())
return false;
QRhi *rhi = m_quickWindow->rhi();
QSSG_ASSERT_X(rhi != nullptr, "No RHI handle!", return false);
if (!d->isMultiViewRenderingEnabled())
emit multiViewRenderingEnabledChanged();
return d->finalizeGraphics(rhi);
}
void QQuick3DXrManager::renderFrame()
{
Q_D(QQuick3DXrManager);
if (!m_xrOrigin) {
if (!m_xrOriginWarningShown) {
qWarning() << "No XrOrigin found!";
m_xrOriginWarningShown = true;
}
return;
}
d->doRenderFrame();
}
void QQuick3DXrManager::preSetupQuickScene()
{
if (!m_renderControl)
m_renderControl = new QQuickRenderControl;
if (!m_quickWindow)
m_quickWindow = new QQuickWindow(m_renderControl);
}
bool QQuick3DXrManager::setupQuickScene()
{
Q_D(QQuick3DXrManager);
d->setupWindow(m_quickWindow);
if (!m_animationDriver) {
m_animationDriver = new QQuick3DXrAnimationDriver;
m_animationDriver->install();
}
const bool initSuccess = m_renderControl->initialize();
if (!initSuccess) {
qWarning("Quick 3D XR: Failed to create renderControl (failed to initialize RHI?)");
return false;
}
QRhi *rhi = m_renderControl->rhi();
if (!rhi) {
qWarning("Quick3D XR: No QRhi from renderControl. This should not happen.");
return false;
}
qCDebug(lcQuick3DXr, "Quick 3D XR: QRhi initialized with backend %s", rhi->backendName());
return true;
}
bool QQuick3DXrManager::supportsPassthrough() const
{
Q_D(const QQuick3DXrManager);
return d->supportsPassthrough();
}
QT_END_NAMESPACE