17#include <QtQuick3DUtils/private/qssgassert_p.h>
18#include <QtQuick3D/private/qquick3dviewport_p.h>
20#include <QtQuick/qquickwindow.h>
21#include <QtQuick/qquickrendercontrol.h>
23#include <QtGui/qquaternion.h>
25#include <QtCore/qobject.h>
27#include <openxr/openxr_reflection.h>
29#ifdef XR_USE_GRAPHICS_API_VULKAN
30# include "qopenxrgraphics_vulkan_p.h"
33#ifdef XR_USE_GRAPHICS_API_D3D11
34# include "qopenxrgraphics_d3d11_p.h"
37#ifdef XR_USE_GRAPHICS_API_D3D12
38# include "qopenxrgraphics_d3d12_p.h"
41#ifdef XR_USE_GRAPHICS_API_OPENGL
42# include "qopenxrgraphics_opengl_p.h"
45#ifdef XR_USE_PLATFORM_ANDROID
46# include <QtCore/qnativeinterface.h>
47# include <QtCore/QJniEnvironment>
48# include <QtCore/QJniObject>
49# ifdef XR_USE_GRAPHICS_API_OPENGL_ES
50# include "qopenxrgraphics_opengles_p.h"
54#ifdef XR_USE_GRAPHICS_API_METAL
55# include "qopenxrgraphics_metal_p.h"
58static XrReferenceSpaceType getXrReferenceSpaceType(QtQuick3DXr::ReferenceSpace referenceSpace)
60 switch (referenceSpace) {
61 case QtQuick3DXr::ReferenceSpace::ReferenceSpaceLocal:
62 return XR_REFERENCE_SPACE_TYPE_LOCAL;
63 case QtQuick3DXr::ReferenceSpace::ReferenceSpaceStage:
64 return XR_REFERENCE_SPACE_TYPE_STAGE;
65 case QtQuick3DXr::ReferenceSpace::ReferenceSpaceLocalFloor:
66 return XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
68 return XR_REFERENCE_SPACE_TYPE_LOCAL;
74 switch (referenceSpace) {
75 case XR_REFERENCE_SPACE_TYPE_LOCAL:
77 case XR_REFERENCE_SPACE_TYPE_STAGE:
79 case XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT:
87#define ENUM_CASE_STR(name, val) case name: return #name;
88#define MAKE_TO_STRING_FUNC(enumType)
89 static inline const char* to_string(enumType e) {
92 default: return "Unknown " #enumType;
102static bool isExtensionSupported(
const char *extensionName,
const QVector<XrExtensionProperties> &instanceExtensionProperties, uint32_t *extensionVersion =
nullptr)
104 for (
const auto &extensionProperty : instanceExtensionProperties) {
105 if (!strcmp(extensionName, extensionProperty.extensionName)) {
106 if (extensionVersion)
107 *extensionVersion = extensionProperty.extensionVersion;
114static bool isApiLayerSupported(
const char *layerName,
const QVector<XrApiLayerProperties> &apiLayerProperties)
116 for (
const auto &prop : apiLayerProperties) {
117 if (!strcmp(layerName, prop.layerName))
127#ifdef XR_EXT_debug_utils
128static XRAPI_ATTR XrBool32 XRAPI_CALL defaultDebugCallbackFunc(XrDebugUtilsMessageSeverityFlagsEXT messageSeverity,
129 XrDebugUtilsMessageTypeFlagsEXT messageType,
130 const XrDebugUtilsMessengerCallbackDataEXT *callbackData,
133 Q_UNUSED(messageSeverity);
134 Q_UNUSED(messageType);
137 qDebug(
"xrDebug [QOpenXRManager %p] %s", self, callbackData->message);
144 XrFrameWaitInfo frameWaitInfo {};
145 frameWaitInfo.type = XR_TYPE_FRAME_WAIT_INFO;
146 XrFrameState frameState {};
147 frameState.type = XR_TYPE_FRAME_STATE;
148 auto result = xrWaitFrame(session, &frameWaitInfo, &frameState);
149 return { result, frameState };
174 return static_cast<QEvent::Type>(event);
179 QCoreApplication::postEvent(
this,
new QEvent(QQuick3DOpenXRThreadWorker::asQEvent(QQuick3DOpenXRThreadWorker::Event::WaitForFrame)));
185 switch (
static_cast<
Event>(event->type())) {
187 auto result = waitForNextFrame(m_session);
188 emit frameWaited(result.first, result.second);
192 return QObject::event(event);
200 XrSession m_session = XR_NULL_HANDLE;
205 m_errorString = QObject::tr(
"%1 for runtime %2 %3 failed with %4.")
206 .arg(QLatin1StringView(callName),
208 m_runtimeVersion.toString(),
209 OpenXRHelpers::getXrResultAsString(result, m_instance));
210 if (result == XR_ERROR_FORM_FACTOR_UNAVAILABLE)
211 m_errorString += QObject::tr(
"\nThe OpenXR runtime has no connection to the headset; check if connection is active and functional.");
227 QSSG_ASSERT(manager !=
nullptr,
return nullptr);
228 return manager->d_func();
231void QQuick3DXrManagerPrivate::updateCameraHelper(QQuick3DXrEyeCamera *camera,
const XrCompositionLayerProjectionView &layerView)
233 camera->setLeftTangent(qTan(layerView.fov.angleLeft));
234 camera->setRightTangent(qTan(layerView.fov.angleRight));
235 camera->setUpTangent(qTan(layerView.fov.angleUp));
236 camera->setDownTangent(qTan(layerView.fov.angleDown));
238 camera->setPosition(QVector3D(layerView.pose.position.x,
239 layerView.pose.position.y,
240 layerView.pose.position.z) * 100.0f);
242 camera->setRotation(QQuaternion(layerView.pose.orientation.w,
243 layerView.pose.orientation.x,
244 layerView.pose.orientation.y,
245 layerView.pose.orientation.z));
252 Q_Q(QQuick3DXrManager);
254 QQuick3DXrOrigin *xrOrigin = q->m_xrOrigin;
256 QQuick3DXrEyeCamera *eyeCamera = xrOrigin ? xrOrigin->eyeCamera(eye) :
nullptr;
259 updateCameraHelper(eyeCamera, layerView);
261 q->m_vrViewport->setCamera(eyeCamera);
267 Q_Q(QQuick3DXrManager);
269 QQuick3DXrOrigin *xrOrigin = q->m_xrOrigin;
270 QQuick3DViewport *vrViewport = q->m_vrViewport;
272 QVarLengthArray<QQuick3DCamera *, 4> cameras;
273 for (
int i = projectionLayerViewStartIndex; i < projectionLayerViewStartIndex + count; ++i) {
274 QQuick3DXrEyeCamera *eyeCamera = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
276 updateCameraHelper(eyeCamera, m_projectionLayerViews[i]);
277 cameras.append(eyeCamera);
279 vrViewport->setMultiViewCameras(cameras.data(), cameras.count());
284 bool supported =
false;
285 XrSystemPassthroughProperties2FB passthroughSystemProperties{};
286 passthroughSystemProperties.type = XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB;
288 XrSystemProperties systemProperties{};
289 systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
290 systemProperties.next = &passthroughSystemProperties;
292 XrSystemGetInfo systemGetInfo{};
293 systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
294 systemGetInfo.formFactor = m_formFactor;
296 XrSystemId systemId = XR_NULL_SYSTEM_ID;
297 xrGetSystem(m_instance, &systemGetInfo, &systemId);
298 xrGetSystemProperties(m_instance, systemId, &systemProperties);
300 supported = (passthroughSystemProperties.capabilities & XR_PASSTHROUGH_CAPABILITY_BIT_FB) == XR_PASSTHROUGH_CAPABILITY_BIT_FB;
306 XrSystemPassthroughPropertiesFB oldPassthroughSystemProperties{};
307 oldPassthroughSystemProperties.type = XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB;
308 systemProperties.next = &oldPassthroughSystemProperties;
309 xrGetSystemProperties(m_instance, systemId, &systemProperties);
310 supported = oldPassthroughSystemProperties.supportsPassthrough;
318 QSSG_ASSERT(window !=
nullptr,
return);
320 m_graphics->setupWindow(window);
325 return m_graphics && m_graphics->rhi();
330 QSSG_ASSERT(window !=
nullptr,
return false);
331 QSSG_ASSERT(m_graphics !=
nullptr,
return false);
333 return m_graphics->setupGraphics(m_instance, m_systemId, window->graphicsConfiguration());
338 Q_Q(QQuick3DXrManager);
339 if (m_waitingForFrame) {
344 QCoreApplication::postEvent(q,
new QEvent(QEvent::UpdateRequest));
349 Q_Q(QQuick3DXrManager);
351 bool exitRenderLoop =
false;
352 bool requestrestart =
false;
353 pollEvents(&exitRenderLoop, &requestrestart);
356 emit q->sessionEnded();
358 if (m_sessionRunning && m_inputManager) {
359 QQuick3DXrInputManagerPrivate::get(m_inputManager)->pollActions();
366 for (
const Swapchain &swapchain : m_swapchains)
367 xrDestroySwapchain(swapchain.handle);
369 m_swapchains.clear();
370 m_swapchainImages.clear();
371 m_configViews.clear();
373 for (
const Swapchain &swapchain : m_depthSwapchains)
374 xrDestroySwapchain(swapchain.handle);
376 m_depthSwapchains.clear();
377 m_depthSwapchainImages.clear();
382 Q_ASSERT(m_session != XR_NULL_HANDLE);
384 if (m_waitingForFrame)
386 m_waitingForFrame =
true;
392 auto result = waitForNextFrame(m_session);
393 onFrameWaitCompleted(result.first, result.second);
399 if (!m_waitingForFrame)
401 m_waitingForFrame =
false;
403 if (!checkXrResult(result)) {
404 qWarning(
"xrWaitFrame failed");
406 doRenderFrameAferWait(frameState);
410 m_wantUpdate =
false;
417 Q_ASSERT(m_session != XR_NULL_HANDLE);
419 XrFrameBeginInfo frameBeginInfo{};
420 frameBeginInfo.type = XR_TYPE_FRAME_BEGIN_INFO;
421 if (!checkXrResult(xrBeginFrame(m_session, &frameBeginInfo))) {
422 qWarning(
"xrBeginFrame failed");
426 QVector<XrCompositionLayerBaseHeader*> layers;
428 XrCompositionLayerPassthroughFB passthroughCompLayer{};
429 passthroughCompLayer.type = XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB;
430 if (m_enablePassthrough && m_passthroughSupported) {
431 if (m_passthroughLayer == XR_NULL_HANDLE)
432 createMetaQuestPassthroughLayer();
433 passthroughCompLayer.layerHandle = m_passthroughLayer;
434 passthroughCompLayer.flags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
435 passthroughCompLayer.space = XR_NULL_HANDLE;
436 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*>(&passthroughCompLayer));
439 XrCompositionLayerProjection layer{};
440 layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
441 layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
442 layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
443 layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
445 if (frameState.shouldRender == XR_TRUE) {
446 if (renderLayer(frameState.predictedDisplayTime, frameState.predictedDisplayPeriod, layer)) {
447 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer));
451 XrFrameEndInfo frameEndInfo{};
452 frameEndInfo.type = XR_TYPE_FRAME_END_INFO;
453 frameEndInfo.displayTime = frameState.predictedDisplayTime;
454 if (!m_enablePassthrough)
455 frameEndInfo.environmentBlendMode = m_environmentBlendMode;
457 frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
458 frameEndInfo.layerCount = (uint32_t)layers.size();
459 frameEndInfo.layers = layers.data();
460 if (!checkXrResult(xrEndFrame(m_session, &frameEndInfo)))
461 qWarning(
"xrEndFrame failed");
466 QSSG_ASSERT(rhi !=
nullptr && m_graphics !=
nullptr,
return false);
468 if (m_multiviewRendering && !rhi->isFeatureSupported(QRhi::MultiView)) {
469 qCDebug(lcQuick3DXr) <<
"Multiview rendering is not supported with the current graphics API";
470 m_multiviewRendering =
false;
473#if QT_CONFIG(graphicsframecapture)
474 if (m_frameCapture) {
475 m_frameCapture->setCapturePath(QLatin1String(
"."));
476 m_frameCapture->setCapturePrefix(QLatin1String(
"quick3dxr"));
477 m_frameCapture->setRhi(rhi);
478 if (!m_frameCapture->isLoaded()) {
479 qWarning(
"Quick 3D XR: Frame capture was requested but QGraphicsFrameCapture is not initialized"
480 " (or has no backends enabled in the Qt build)");
482 qCDebug(lcQuick3DXr,
"Quick 3D XR: Frame capture initialized");
487 m_isGraphicsInitialized = m_graphics->finializeGraphics(rhi);
488 return m_isGraphicsInitialized;
493 Q_Q(QQuick3DXrManager);
499 if (qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_FRAME_CAPTURE")) {
500#if QT_CONFIG(graphicsframecapture)
501 m_frameCapture.reset(
new QGraphicsFrameCapture);
503 qWarning(
"Quick 3D XR: Frame capture was requested, but Qt is built without QGraphicsFrameCapture");
507#ifdef XR_USE_PLATFORM_ANDROID
509 PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
510 xrGetInstanceProcAddr(
511 XR_NULL_HANDLE,
"xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
512 if (xrInitializeLoaderKHR != NULL) {
513 m_javaVM = QJniEnvironment::javaVM();
514 m_androidActivity = QNativeInterface::QAndroidApplication::context();
516 XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
517 memset(&loaderInitializeInfoAndroid, 0,
sizeof(loaderInitializeInfoAndroid));
518 loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
519 loaderInitializeInfoAndroid.next = NULL;
520 loaderInitializeInfoAndroid.applicationVM = m_javaVM;
521 loaderInitializeInfoAndroid.applicationContext = m_androidActivity.object();
522 XrResult xrResult = xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
523 if (xrResult != XR_SUCCESS) {
524 qWarning(
"Failed to initialize OpenXR Loader: %s", to_string(xrResult));
531 auto graphicsAPI = QQuickWindow::graphicsApi();
533 m_graphics =
nullptr;
534#ifdef XR_USE_GRAPHICS_API_VULKAN
535 if (graphicsAPI == QSGRendererInterface::Vulkan)
536 m_graphics =
new QOpenXRGraphicsVulkan;
538#ifdef XR_USE_GRAPHICS_API_D3D11
539 if (graphicsAPI == QSGRendererInterface::Direct3D11)
540 m_graphics =
new QOpenXRGraphicsD3D11;
542#ifdef XR_USE_GRAPHICS_API_D3D12
543 if (graphicsAPI == QSGRendererInterface::Direct3D12)
544 m_graphics =
new QOpenXRGraphicsD3D12;
546#ifdef XR_USE_GRAPHICS_API_OPENGL
547 if (graphicsAPI == QSGRendererInterface::OpenGL)
548 m_graphics =
new QOpenXRGraphicsOpenGL;
550#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
551 if (graphicsAPI == QSGRendererInterface::OpenGL)
552 m_graphics =
new QOpenXRGraphicsOpenGLES;
554#ifdef XR_USE_GRAPHICS_API_METAL
555 if (graphicsAPI == QSGRendererInterface::Metal)
556 m_graphics =
new QOpenXRGraphicsMetal;
560 qWarning() <<
"The Qt Quick Scenegraph is not using a supported RHI mode:" << graphicsAPI;
565 checkXrExtensions(
nullptr);
568 m_spaceExtension = QQuick3DXrAnchorManager::instance();
571 XrResult result = createXrInstance();
572 if (result != XR_SUCCESS) {
573 setErrorString(result,
"xrCreateInstance");
575 m_graphics =
nullptr;
582 setupDebugMessenger();
585 result = initializeSystem();
586 if (result != XR_SUCCESS) {
587 setErrorString(result,
"xrGetSystem");
589 m_graphics =
nullptr;
594 if (!q->setupGraphics()) {
595 m_errorString = QObject::tr(
"Failed to set up 3D API integration");
597 m_graphics =
nullptr;
602 XrSessionCreateInfo xrSessionInfo{};
603 xrSessionInfo.type = XR_TYPE_SESSION_CREATE_INFO;
604 xrSessionInfo.next = m_graphics->handle();
605 xrSessionInfo.systemId = m_systemId;
607 result = xrCreateSession(m_instance, &xrSessionInfo, &m_session);
608 if (result != XR_SUCCESS) {
609 setErrorString(result,
"xrCreateSession");
611 m_graphics =
nullptr;
615 const bool disableAsyncWait = qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_DISABLE_ASYNC_WAIT") != 0;
616 if (Q_LIKELY(!disableAsyncWait))
620 if (m_colorspaceExtensionSupported)
621 setupMetaQuestColorSpaces();
622 if (m_displayRefreshRateExtensionSupported)
623 setupMetaQuestRefreshRates();
624 if (m_spaceExtensionSupported)
625 m_spaceExtension->initialize(m_instance, m_session);
627 checkReferenceSpaces();
630 m_inputManager = QQuick3DXrInputManager::instance();
631 if (QSSG_GUARD(m_inputManager !=
nullptr))
632 QQuick3DXrInputManagerPrivate::get(m_inputManager)->init(m_instance, m_session);
634 if (!setupAppSpace())
636 if (!setupViewSpace())
639 if (!createSwapchains())
647 m_waitingForFrame =
false;
648 m_wantUpdate =
false;
649 destroyWorkerThread();
651 if (m_inputManager) {
652 QQuick3DXrInputManagerPrivate::get(m_inputManager)->teardown();
653 m_inputManager =
nullptr;
656 if (m_spaceExtension) {
658 m_spaceExtension =
nullptr;
661 if (m_passthroughLayer)
662 destroyMetaQuestPassthroughLayer();
663 if (m_passthroughFeature)
664 destroyMetaQuestPassthrough();
668 if (m_appSpace != XR_NULL_HANDLE) {
669 xrDestroySpace(m_appSpace);
672 if (m_viewSpace != XR_NULL_HANDLE)
673 xrDestroySpace(m_viewSpace);
675 xrDestroySession(m_session);
677#ifdef XR_EXT_debug_utils
678 if (m_debugMessenger) {
679 m_xrDestroyDebugUtilsMessengerEXT(m_debugMessenger);
680 m_debugMessenger = XR_NULL_HANDLE;
684 xrDestroyInstance(m_instance);
689 m_graphics->releaseResources();
694 Q_Q(QQuick3DXrManager);
696 qCDebug(lcQuick3DXr,
"Initializing OpenXR worker thread");
697 m_workerThread =
new QThread();
700 m_worker =
new QQuick3DOpenXRThreadWorker(m_session);
701 m_worker->moveToThread(m_workerThread);
705 &QQuick3DOpenXRThreadWorker::frameWaited,
707 [
this](XrResult result,
const XrFrameState &frameState) { onFrameWaitCompleted(result, frameState); },
708 Qt::QueuedConnection);
710 QObject::connect(m_workerThread, &QThread::finished, m_worker, &QObject::deleteLater);
712 m_workerThread->start();
717 if (m_workerThread) {
718 m_workerThread->quit();
719 m_workerThread->wait();
720 delete m_workerThread;
721 m_workerThread =
nullptr;
723 qCDebug(lcQuick3DXr,
"OpenXR worker thread destroyed");
729 Q_ASSERT(m_session != XR_NULL_HANDLE);
732 if (!checkXrResult(xrEnumerateReferenceSpaces(m_session, 0, &spaceCount,
nullptr))) {
733 qWarning(
"Failed to enumerate reference spaces");
736 m_availableReferenceSpace.resize(spaceCount);
737 if (!checkXrResult(xrEnumerateReferenceSpaces(m_session, spaceCount, &spaceCount, m_availableReferenceSpace.data()))) {
738 qWarning(
"Failed to enumerate reference spaces");
742 qCDebug(lcQuick3DXr,
"Available reference spaces: %d", spaceCount);
743 for (XrReferenceSpaceType space : m_availableReferenceSpace) {
744 qCDebug(lcQuick3DXr,
" Name: %s", to_string(space));
750 return m_availableReferenceSpace.contains(type);
755 Q_Q(QQuick3DXrManager);
757 Q_ASSERT(m_session != XR_NULL_HANDLE);
759 XrPosef identityPose;
760 identityPose.orientation.w = 1;
761 identityPose.orientation.x = 0;
762 identityPose.orientation.y = 0;
763 identityPose.orientation.z = 0;
764 identityPose.position.x = 0;
765 identityPose.position.y = 0;
766 identityPose.position.z = 0;
768 XrReferenceSpaceType newReferenceSpace;
769 XrSpace newAppSpace = XR_NULL_HANDLE;
770 m_isEmulatingLocalFloor =
false;
772 if (isReferenceSpaceAvailable(m_requestedReferenceSpace)) {
773 newReferenceSpace = m_requestedReferenceSpace;
774 }
else if (m_requestedReferenceSpace == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT &&
775 isReferenceSpaceAvailable(XR_REFERENCE_SPACE_TYPE_STAGE)) {
776 m_isEmulatingLocalFloor =
true;
777 m_isFloorResetPending =
true;
778 newReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
780 qWarning(
"Requested reference space is not available");
781 newReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
785 qCDebug(lcQuick3DXr,
"Creating new reference space for app space: %s", to_string(newReferenceSpace));
786 XrReferenceSpaceCreateInfo referenceSpaceCreateInfo{};
787 referenceSpaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
788 referenceSpaceCreateInfo.poseInReferenceSpace = identityPose;
789 referenceSpaceCreateInfo.referenceSpaceType = newReferenceSpace;
790 if (!checkXrResult(xrCreateReferenceSpace(m_session, &referenceSpaceCreateInfo, &newAppSpace))) {
791 qWarning(
"Failed to create app space");
796 xrDestroySpace(m_appSpace);
798 m_appSpace = newAppSpace;
799 m_referenceSpace = newReferenceSpace;
802 if (!m_isFloorResetPending)
803 emit q->referenceSpaceChanged();
811 Q_Q(QQuick3DXrManager);
815 if (m_requestedReferenceSpace != m_referenceSpace && !m_isFloorResetPending) {
816 if (!setupAppSpace()) {
818 qWarning(
"Setting requested reference space failed");
819 m_requestedReferenceSpace = m_referenceSpace;
828 if (m_isFloorResetPending) {
829 if (!resetEmulatedFloorHeight(predictedDisplayTime)) {
831 m_requestedReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
832 emit q->referenceSpaceChanged();
841 Q_ASSERT(m_session != XR_NULL_HANDLE);
843 XrPosef identityPose;
844 identityPose.orientation.w = 1;
845 identityPose.orientation.x = 0;
846 identityPose.orientation.y = 0;
847 identityPose.orientation.z = 0;
848 identityPose.position.x = 0;
849 identityPose.position.y = 0;
850 identityPose.position.z = 0;
852 XrSpace newViewSpace = XR_NULL_HANDLE;
854 XrReferenceSpaceCreateInfo referenceSpaceCreateInfo{};
855 referenceSpaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
856 referenceSpaceCreateInfo.poseInReferenceSpace = identityPose;
857 referenceSpaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
858 if (!checkXrResult(xrCreateReferenceSpace(m_session, &referenceSpaceCreateInfo, &newViewSpace))) {
859 qWarning(
"Failed to create view space");
863 if (m_viewSpace != XR_NULL_HANDLE)
864 xrDestroySpace(m_viewSpace);
866 m_viewSpace = newViewSpace;
873 Q_Q(QQuick3DXrManager);
875 Q_ASSERT(m_isEmulatingLocalFloor);
877 m_isFloorResetPending =
false;
879 XrPosef identityPose;
880 identityPose.orientation.w = 1;
881 identityPose.orientation.x = 0;
882 identityPose.orientation.y = 0;
883 identityPose.orientation.z = 0;
884 identityPose.position.x = 0;
885 identityPose.position.y = 0;
886 identityPose.position.z = 0;
888 XrSpace localSpace = XR_NULL_HANDLE;
889 XrSpace stageSpace = XR_NULL_HANDLE;
891 XrReferenceSpaceCreateInfo createInfo{};
892 createInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
893 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
894 createInfo.poseInReferenceSpace = identityPose;
896 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &localSpace))) {
897 qWarning(
"Failed to create local space (for emulated LOCAL_FLOOR space)");
901 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
902 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &stageSpace))) {
903 qWarning(
"Failed to create stage space (for emulated LOCAL_FLOOR space)");
904 xrDestroySpace(localSpace);
908 XrSpaceLocation stageLocation{};
909 stageLocation.type = XR_TYPE_SPACE_LOCATION;
910 stageLocation.pose = identityPose;
912 if (!checkXrResult(xrLocateSpace(stageSpace, localSpace, predictedDisplayTime, &stageLocation))) {
913 qWarning(
"Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR");
914 xrDestroySpace(localSpace);
915 xrDestroySpace(stageSpace);
919 xrDestroySpace(localSpace);
920 xrDestroySpace(stageSpace);
922 XrSpace newAppSpace = XR_NULL_HANDLE;
923 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
924 createInfo.poseInReferenceSpace.position.y = stageLocation.pose.position.y;
925 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &newAppSpace))) {
926 qWarning(
"Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate");
930 xrDestroySpace(m_appSpace);
931 m_appSpace = newAppSpace;
932 m_referenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
933 emit q->referenceSpaceChanged();
940 Q_ASSERT(m_session != XR_NULL_HANDLE);
941 Q_ASSERT(m_configViews.isEmpty());
942 Q_ASSERT(m_swapchains.isEmpty());
944 XrSystemProperties systemProperties{};
945 systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
947 XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties{};
948 handTrackingSystemProperties.type = XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT;
949 systemProperties.next = &handTrackingSystemProperties;
951 if (!checkXrResult(xrGetSystemProperties(m_instance, m_systemId, &systemProperties))) {
952 qWarning(
"Failed to get OpenXR system properties");
955 qCDebug(lcQuick3DXr,
"System Properties: Name=%s VendorId=%d", systemProperties.systemName, systemProperties.vendorId);
956 qCDebug(lcQuick3DXr,
"System Graphics Properties: MaxWidth=%d MaxHeight=%d MaxLayers=%d",
957 systemProperties.graphicsProperties.maxSwapchainImageWidth,
958 systemProperties.graphicsProperties.maxSwapchainImageHeight,
959 systemProperties.graphicsProperties.maxLayerCount);
960 qCDebug(lcQuick3DXr,
"System Tracking Properties: OrientationTracking=%s PositionTracking=%s",
961 systemProperties.trackingProperties.orientationTracking == XR_TRUE ?
"True" :
"False",
962 systemProperties.trackingProperties.positionTracking == XR_TRUE ?
"True" :
"False");
963 qCDebug(lcQuick3DXr,
"System Hand Tracking Properties: handTracking=%s",
964 handTrackingSystemProperties.supportsHandTracking == XR_TRUE ?
"True" :
"False");
968 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
975 qWarning(
"Failed to enumerate view configurations");
978 m_configViews.resize(viewCount, {XR_TYPE_VIEW_CONFIGURATION_VIEW,
nullptr, 0, 0, 0, 0, 0, 0});
979 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
984 m_configViews.data())))
986 qWarning(
"Failed to enumerate view configurations");
989 m_views.resize(viewCount, {XR_TYPE_VIEW,
nullptr, {}, {}});
990 m_projectionLayerViews.resize(viewCount, {});
991 m_layerDepthInfos.resize(viewCount, {});
996 uint32_t swapchainFormatCount;
997 if (!checkXrResult(xrEnumerateSwapchainFormats(m_session, 0, &swapchainFormatCount,
nullptr))) {
998 qWarning(
"Failed to enumerate swapchain formats");
1001 QVector<int64_t> swapchainFormats(swapchainFormatCount);
1002 if (!checkXrResult(xrEnumerateSwapchainFormats(m_session,
1003 swapchainFormats.size(),
1004 &swapchainFormatCount,
1005 swapchainFormats.data())))
1007 qWarning(
"Failed to enumerate swapchain formats");
1011 Q_ASSERT(
static_cast<qsizetype>(swapchainFormatCount) == swapchainFormats.size());
1012 m_colorSwapchainFormat = m_graphics->colorSwapchainFormat(swapchainFormats);
1013 if (m_compositionLayerDepthSupported)
1014 m_depthSwapchainFormat = m_graphics->depthSwapchainFormat(swapchainFormats);
1018 QString swapchainFormatsString;
1019 for (int64_t format : swapchainFormats) {
1020 const bool selectedColor = format == m_colorSwapchainFormat;
1021 const bool selectedDepth = format == m_depthSwapchainFormat;
1022 swapchainFormatsString += u" ";
1024 swapchainFormatsString += u"[";
1025 else if (selectedDepth)
1026 swapchainFormatsString += u"<";
1027 swapchainFormatsString += QString::number(format);
1029 swapchainFormatsString += u"]";
1030 else if (selectedDepth)
1031 swapchainFormatsString += u">";
1033 qCDebug(lcQuick3DXr,
"Swapchain formats: %s", qPrintable(swapchainFormatsString));
1036 const XrViewConfigurationView &vp = m_configViews[0];
1047 if (m_multiviewRendering) {
1049 XrSwapchainCreateInfo swapchainCreateInfo{};
1050 swapchainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
1051 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT;
1052 swapchainCreateInfo.format = m_colorSwapchainFormat;
1053 swapchainCreateInfo.sampleCount = 1;
1054 swapchainCreateInfo.width = vp.recommendedImageRectWidth;
1055 swapchainCreateInfo.height = vp.recommendedImageRectHeight;
1056 swapchainCreateInfo.faceCount = 1;
1057 swapchainCreateInfo.arraySize = viewCount;
1058 swapchainCreateInfo.mipCount = 1;
1060 qCDebug(lcQuick3DXr,
"Creating multiview swapchain for %u view(s) with dimensions Width=%d Height=%d SampleCount=%d Format=%llx",
1062 vp.recommendedImageRectWidth,
1063 vp.recommendedImageRectHeight,
1065 static_cast<
long long unsigned int>(m_colorSwapchainFormat));
1067 Swapchain swapchain;
1068 swapchain.width = swapchainCreateInfo.width;
1069 swapchain.height = swapchainCreateInfo.height;
1070 swapchain.arraySize = swapchainCreateInfo.arraySize;
1071 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1072 uint32_t imageCount = 0;
1073 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1074 qWarning(
"Failed to enumerate swapchain images");
1078 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1079 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1080 qWarning(
"Failed to enumerate swapchain images");
1084 m_swapchains.append(swapchain);
1085 m_swapchainImages.insert(swapchain.handle, swapchainImages);
1087 qWarning(
"xrCreateSwapchain failed (multiview)");
1095 if (m_compositionLayerDepthSupported && m_depthSwapchainFormat > 0) {
1096 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1097 swapchainCreateInfo.format = m_depthSwapchainFormat;
1098 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1099 uint32_t imageCount = 0;
1100 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1101 qWarning(
"Failed to enumerate depth swapchain images");
1105 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1106 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1107 qWarning(
"Failed to enumerate depth swapchain images");
1111 m_depthSwapchains.append(swapchain);
1112 m_depthSwapchainImages.insert(swapchain.handle, swapchainImages);
1114 qWarning(
"xrCreateSwapchain failed for depth swapchain (multiview)");
1120 for (uint32_t i = 0; i < viewCount; i++) {
1121 qCDebug(lcQuick3DXr,
"Creating swapchain for view %u with dimensions Width=%d Height=%d SampleCount=%d Format=%llx",
1123 vp.recommendedImageRectWidth,
1124 vp.recommendedImageRectHeight,
1126 static_cast<
long long unsigned int>(m_colorSwapchainFormat));
1129 XrSwapchainCreateInfo swapchainCreateInfo{};
1130 swapchainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
1131 swapchainCreateInfo.arraySize = 1;
1132 swapchainCreateInfo.format = m_colorSwapchainFormat;
1133 swapchainCreateInfo.width = vp.recommendedImageRectWidth;
1134 swapchainCreateInfo.height = vp.recommendedImageRectHeight;
1135 swapchainCreateInfo.mipCount = 1;
1136 swapchainCreateInfo.faceCount = 1;
1137 swapchainCreateInfo.sampleCount = 1;
1138 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
1139 Swapchain swapchain;
1140 swapchain.width = swapchainCreateInfo.width;
1141 swapchain.height = swapchainCreateInfo.height;
1142 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1143 uint32_t imageCount = 0;
1144 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1145 qWarning(
"Failed to enumerate swapchain images");
1149 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1150 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1151 qWarning(
"Failed to enumerate swapchain images");
1155 m_swapchains.append(swapchain);
1156 m_swapchainImages.insert(swapchain.handle, swapchainImages);
1158 qWarning(
"xrCreateSwapchain failed (view %u)", viewCount);
1162 if (m_compositionLayerDepthSupported && m_depthSwapchainFormat > 0) {
1163 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1164 swapchainCreateInfo.format = m_depthSwapchainFormat;
1165 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1166 uint32_t imageCount = 0;
1167 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1168 qWarning(
"Failed to enumerate depth swapchain images");
1172 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1173 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1174 qWarning(
"Failed to enumerate depth swapchain images");
1178 m_depthSwapchains.append(swapchain);
1179 m_depthSwapchainImages.insert(swapchain.handle, swapchainImages);
1181 qWarning(
"xrCreateSwapchain failed for depth swapchain (view %u)", viewCount);
1188 if (m_multiviewRendering) {
1189 if (m_swapchains.isEmpty())
1191 if (m_compositionLayerDepthSupported && m_depthSwapchains.isEmpty())
1194 if (m_swapchains.count() != qsizetype(viewCount))
1196 if (m_compositionLayerDepthSupported && m_depthSwapchains.count() != qsizetype(viewCount))
1201 for (uint32_t i = 0; i < viewCount; ++i) {
1202 m_projectionLayerViews[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
1203 m_projectionLayerViews[i].next =
nullptr;
1204 m_projectionLayerViews[i].subImage.swapchain = m_swapchains[0].handle;
1205 m_projectionLayerViews[i].subImage.imageArrayIndex = i;
1206 m_projectionLayerViews[i].subImage.imageRect.offset.x = 0;
1207 m_projectionLayerViews[i].subImage.imageRect.offset.y = 0;
1208 m_projectionLayerViews[i].subImage.imageRect.extent.width = vp.recommendedImageRectWidth;
1209 m_projectionLayerViews[i].subImage.imageRect.extent.height = vp.recommendedImageRectHeight;
1211 if (m_compositionLayerDepthSupported) {
1212 m_layerDepthInfos[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
1213 m_layerDepthInfos[i].next =
nullptr;
1214 m_layerDepthInfos[i].subImage.swapchain = m_depthSwapchains[0].handle;
1215 m_layerDepthInfos[i].subImage.imageArrayIndex = i;
1216 m_layerDepthInfos[i].subImage.imageRect.offset.x = 0;
1217 m_layerDepthInfos[i].subImage.imageRect.offset.y = 0;
1218 m_layerDepthInfos[i].subImage.imageRect.extent.width = vp.recommendedImageRectWidth;
1219 m_layerDepthInfos[i].subImage.imageRect.extent.height = vp.recommendedImageRectHeight;
1224 if (m_foveationExtensionSupported)
1225 setupMetaQuestFoveation();
1232 if (m_samples == samples)
1235 m_samples = samples;
1243 return m_enabledExtensions;
1248 return m_runtimeName;
1253 return m_runtimeVersion;
1258 Q_Q(QQuick3DXrManager);
1259 QRhi *rhi = q->m_renderControl->rhi();
1260 if (m_multiviewRendering == enable || !rhi)
1262 if (enable && !rhi->isFeatureSupported(QRhi::MultiView)) {
1263 qWarning(
"Quick 3D XR: Multiview rendering was enabled, but is reported as unsupported from the current QRhi backend (%s)",
1264 rhi->backendName());
1267 m_multiviewRendering = enable;
1268 qCDebug(lcQuick3DXr,
"Multiview rendering %s", m_multiviewRendering ?
"enabled" :
"disabled");
1269 if (!m_swapchains.isEmpty()) {
1270 qCDebug(lcQuick3DXr,
"OpenXR swapchain already exists, creating new one due to change in multiview mode");
1274 emit q->multiViewRenderingEnabledChanged();
1282 if (m_passthroughSupported) {
1283 m_enablePassthrough = enable;
1284 if (m_enablePassthrough) {
1285 if (m_passthroughFeature == XR_NULL_HANDLE)
1286 createMetaQuestPassthrough();
1288 startMetaQuestPassthrough();
1290 if (m_passthroughLayer == XR_NULL_HANDLE)
1291 createMetaQuestPassthroughLayer();
1293 resumeMetaQuestPassthroughLayer();
1296 if (m_passthroughLayer)
1297 pauseMetaQuestPassthroughLayer();
1299 if (m_passthroughFeature)
1300 pauseMetaQuestPassthrough();
1303 return m_passthroughSupported;
1308 if (m_submitLayerDepth == enable)
1311 if (m_compositionLayerDepthSupported) {
1313 qCDebug(lcQuick3DXr,
"Enabling submitLayerDepth");
1315 m_submitLayerDepth = enable;
1321 XrReferenceSpaceType referenceSpace = getXrReferenceSpaceType(newReferenceSpace);
1322 if (m_referenceSpace == referenceSpace)
1325 m_requestedReferenceSpace = referenceSpace;
1333 return getReferenceSpaceType(m_referenceSpace);
1344 *exitRenderLoop =
false;
1345 *requestRestart =
false;
1347 auto readNextEvent = [
this]() {
1350 XrEventDataBaseHeader* baseHeader =
reinterpret_cast<XrEventDataBaseHeader*>(&m_eventDataBuffer);
1351 *baseHeader = {XR_TYPE_EVENT_DATA_BUFFER,
nullptr};
1352 const XrResult xr = xrPollEvent(m_instance, &m_eventDataBuffer);
1353 if (xr == XR_SUCCESS) {
1354 if (baseHeader->type == XR_TYPE_EVENT_DATA_EVENTS_LOST) {
1355 const XrEventDataEventsLost*
const eventsLost =
reinterpret_cast<
const XrEventDataEventsLost*>(baseHeader);
1356 qCDebug(lcQuick3DXr,
"%d events lost", eventsLost->lostEventCount);
1362 return static_cast<XrEventDataBaseHeader*>(
nullptr);
1365 auto handleSessionStateChangedEvent = [
this](
const XrEventDataSessionStateChanged& stateChangedEvent,
1366 bool* exitRenderLoop,
1367 bool* requestRestart) {
1368 const XrSessionState oldState = m_sessionState;
1369 m_sessionState = stateChangedEvent.state;
1371 qCDebug(lcQuick3DXr,
"XrEventDataSessionStateChanged: state %s->%s time=%lld",
1372 to_string(oldState),
1373 to_string(m_sessionState),
1374 static_cast<
long long int>(stateChangedEvent.time));
1376 if ((stateChangedEvent.session != XR_NULL_HANDLE) && (stateChangedEvent.session != m_session)) {
1377 qCDebug(lcQuick3DXr,
"XrEventDataSessionStateChanged for unknown session");
1381 switch (m_sessionState) {
1382 case XR_SESSION_STATE_READY: {
1383 Q_ASSERT(m_session != XR_NULL_HANDLE);
1384 XrSessionBeginInfo sessionBeginInfo{};
1385 sessionBeginInfo.type = XR_TYPE_SESSION_BEGIN_INFO;
1386 sessionBeginInfo.primaryViewConfigurationType = m_viewConfigType;
1387 if (!checkXrResult(xrBeginSession(m_session, &sessionBeginInfo))) {
1388 qWarning(
"xrBeginSession failed");
1391 m_sessionRunning =
true;
1394 case XR_SESSION_STATE_STOPPING: {
1395 Q_ASSERT(m_session != XR_NULL_HANDLE);
1396 m_sessionRunning =
false;
1397 if (!checkXrResult(xrEndSession(m_session)))
1398 qWarning(
"xrEndSession failed");
1401 case XR_SESSION_STATE_EXITING: {
1402 *exitRenderLoop =
true;
1404 *requestRestart =
false;
1407 case XR_SESSION_STATE_LOSS_PENDING: {
1408 *exitRenderLoop =
true;
1410 *requestRestart =
true;
1419 while (
const XrEventDataBaseHeader* event = readNextEvent()) {
1420 switch (event->type) {
1421 case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
1422 const auto& instanceLossPending = *
reinterpret_cast<
const XrEventDataInstanceLossPending*>(event);
1423 qCDebug(lcQuick3DXr,
"XrEventDataInstanceLossPending by %lld",
static_cast<
long long int>(instanceLossPending.lossTime));
1424 *exitRenderLoop =
true;
1425 *requestRestart =
true;
1428 case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
1429 auto sessionStateChangedEvent = *
reinterpret_cast<
const XrEventDataSessionStateChanged*>(event);
1430 handleSessionStateChangedEvent(sessionStateChangedEvent, exitRenderLoop, requestRestart);
1433 case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
1435 case XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB:
1436 case XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB:
1437 case XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB:
1438 case XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB:
1440 if (m_spaceExtension)
1441 m_spaceExtension->handleEvent(event);
1443 case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
1445 qCDebug(lcQuick3DXr,
"Ignoring event type %d", event->type);
1453 XrDuration predictedDisplayPeriod,
1454 XrCompositionLayerProjection &layer)
1456 Q_Q(QQuick3DXrManager);
1457 auto *xrOrigin = q->m_xrOrigin;
1458 auto *animationDriver = q->m_animationDriver;
1459 auto *renderControl = q->m_renderControl;
1463 XrViewState viewState{};
1464 viewState.type = XR_TYPE_VIEW_STATE;
1465 quint32 viewCapacityInput = m_views.size();
1466 quint32 viewCountOutput;
1469 updateAppSpace(predictedDisplayTime);
1471 XrViewLocateInfo viewLocateInfo{};
1472 viewLocateInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
1473 viewLocateInfo.viewConfigurationType = m_viewConfigType;
1474 viewLocateInfo.displayTime = predictedDisplayTime;
1475 viewLocateInfo.space = m_appSpace;
1477 res = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCapacityInput, &viewCountOutput, m_views.data());
1478 if (XR_UNQUALIFIED_SUCCESS(res)) {
1479 Q_ASSERT(viewCountOutput == viewCapacityInput);
1480 Q_ASSERT(
static_cast<qsizetype>(viewCountOutput) == m_configViews.size());
1481 Q_ASSERT(
static_cast<qsizetype>(viewCountOutput) == m_projectionLayerViews.size());
1482 Q_ASSERT(m_multiviewRendering ? viewCountOutput == m_swapchains[0].arraySize :
static_cast<qsizetype>(viewCountOutput) == m_swapchains.size());
1485 XrSpaceLocation location{};
1486 location.type = XR_TYPE_SPACE_LOCATION;
1487 if (checkXrResult(xrLocateSpace(m_viewSpace, m_appSpace, predictedDisplayTime, &location))) {
1488 QVector3D position = QVector3D(location.pose.position.x,
1489 location.pose.position.y,
1490 location.pose.position.z) * 100.0f;
1491 QQuaternion rotation(location.pose.orientation.w,
1492 location.pose.orientation.x,
1493 location.pose.orientation.y,
1494 location.pose.orientation.z);
1496 xrOrigin->updateTrackedCamera(position, rotation);
1500 if (QSSG_GUARD(m_inputManager !=
nullptr))
1501 QQuick3DXrInputManagerPrivate::get(m_inputManager)->updatePoses(predictedDisplayTime, m_appSpace);
1504 if (m_spaceExtension)
1505 m_spaceExtension->updateAnchors(predictedDisplayTime, m_appSpace);
1507 if (m_handtrackingExtensionSupported && m_inputManager)
1508 QQuick3DXrInputManagerPrivate::get(m_inputManager)->updateHandtracking(predictedDisplayTime, m_appSpace, m_handtrackingAimExtensionSupported);
1513 const qint64 displayPeriodMS = predictedDisplayPeriod / 1000000;
1514 const qint64 displayDeltaMS = (predictedDisplayTime - m_previousTime) / 1000000;
1516 if (m_previousTime == 0 || !animationDriver->isRunning()) {
1517 animationDriver->setStep(displayPeriodMS);
1519 if (displayDeltaMS > displayPeriodMS)
1520 animationDriver->setStep(displayPeriodMS);
1522 animationDriver->setStep(displayDeltaMS);
1523 animationDriver->advance();
1525 m_previousTime = predictedDisplayTime;
1527#if QT_CONFIG(graphicsframecapture)
1529 m_frameCapture->startCaptureFrame();
1532 if (m_submitLayerDepth && m_samples > 1) {
1533 if (!renderControl->rhi()->isFeatureSupported(QRhi::ResolveDepthStencil)) {
1534 static bool warned =
false;
1537 qWarning(
"Quick3D XR: Submitting depth buffer with MSAA cannot be enabled"
1538 " when depth-stencil resolve is not supported by the underlying 3D API (%s)",
1539 renderControl->rhi()->backendName());
1541 m_submitLayerDepth =
false;
1545 if (m_multiviewRendering) {
1546 const Swapchain swapchain = m_swapchains[0];
1549 XrSwapchainImageAcquireInfo acquireInfo{};
1550 acquireInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
1551 uint32_t swapchainImageIndex = 0;
1552 if (!checkXrResult(xrAcquireSwapchainImage(swapchain.handle, &acquireInfo, &swapchainImageIndex))) {
1553 qWarning(
"Failed to acquire swapchain image (multiview)");
1556 XrSwapchainImageWaitInfo waitInfo{};
1557 waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
1558 waitInfo.timeout = XR_INFINITE_DURATION;
1559 if (!checkXrResult(xrWaitSwapchainImage(swapchain.handle, &waitInfo))) {
1560 qWarning(
"Failed to wait for swapchain image (multiview)");
1563 XrSwapchainImageBaseHeader *swapchainImage = m_swapchainImages[swapchain.handle][swapchainImageIndex];
1565 XrSwapchainImageBaseHeader *depthSwapchainImage =
nullptr;
1566 if (m_submitLayerDepth && !m_depthSwapchains.isEmpty()) {
1567 if (checkXrResult(xrAcquireSwapchainImage(m_depthSwapchains[0].handle, &acquireInfo, &swapchainImageIndex))) {
1568 if (checkXrResult(xrWaitSwapchainImage(m_depthSwapchains[0].handle, &waitInfo)))
1569 depthSwapchainImage = m_depthSwapchainImages[m_depthSwapchains[0].handle][swapchainImageIndex];
1571 qWarning(
"Failed to wait for depth swapchain image (multiview)");
1573 qWarning(
"Failed to acquire depth swapchain image (multiview)");
1580 for (uint32_t i = 0; i < viewCountOutput; i++) {
1582 m_projectionLayerViews[i].pose = m_views[i].pose;
1583 m_projectionLayerViews[i].fov = m_views[i].fov;
1585 updateCameraMultiview(0, viewCountOutput);
1591 doRender(m_projectionLayerViews[0].subImage,
1593 depthSwapchainImage);
1595 for (uint32_t i = 0; i < viewCountOutput; i++) {
1596 if (m_submitLayerDepth) {
1597 m_layerDepthInfos[i].minDepth = 0;
1598 m_layerDepthInfos[i].maxDepth = 1;
1599 QQuick3DXrEyeCamera *cam = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
1600 m_layerDepthInfos[i].nearZ = cam ? cam->clipNear() : 1.0f;
1601 m_layerDepthInfos[i].farZ = cam ? cam->clipFar() : 10000.0f;
1602 m_projectionLayerViews[i].next = &m_layerDepthInfos[i];
1604 m_projectionLayerViews[i].next =
nullptr;
1609 XrSwapchainImageReleaseInfo releaseInfo{};
1610 releaseInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
1611 if (!checkXrResult(xrReleaseSwapchainImage(swapchain.handle, &releaseInfo)))
1612 qWarning(
"Failed to release swapchain image");
1613 if (depthSwapchainImage) {
1614 if (!checkXrResult(xrReleaseSwapchainImage(m_depthSwapchains[0].handle, &releaseInfo)))
1615 qWarning(
"Failed to release depth swapchain image");
1618 for (uint32_t i = 0; i < viewCountOutput; i++) {
1620 const Swapchain viewSwapchain = m_swapchains[i];
1623 XrSwapchainImageAcquireInfo acquireInfo{};
1624 acquireInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
1625 uint32_t swapchainImageIndex = 0;
1626 if (!checkXrResult(xrAcquireSwapchainImage(viewSwapchain.handle, &acquireInfo, &swapchainImageIndex))) {
1627 qWarning(
"Failed to acquire swapchain image");
1630 XrSwapchainImageWaitInfo waitInfo{};
1631 waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
1632 waitInfo.timeout = XR_INFINITE_DURATION;
1633 if (!checkXrResult(xrWaitSwapchainImage(viewSwapchain.handle, &waitInfo))) {
1634 qWarning(
"Failed to wait for swapchain image");
1637 XrSwapchainImageBaseHeader *swapchainImage = m_swapchainImages[viewSwapchain.handle][swapchainImageIndex];
1639 XrSwapchainImageBaseHeader *depthSwapchainImage =
nullptr;
1640 if (m_submitLayerDepth && !m_depthSwapchains.isEmpty()) {
1641 if (checkXrResult(xrAcquireSwapchainImage(m_depthSwapchains[i].handle, &acquireInfo, &swapchainImageIndex))) {
1642 if (checkXrResult(xrWaitSwapchainImage(m_depthSwapchains[i].handle, &waitInfo)))
1643 depthSwapchainImage = m_depthSwapchainImages[m_depthSwapchains[i].handle][swapchainImageIndex];
1645 qWarning(
"Failed to wait for depth swapchain image");
1647 qWarning(
"Failed to acquire depth swapchain image");
1651 m_projectionLayerViews[i].subImage.swapchain = viewSwapchain.handle;
1652 m_projectionLayerViews[i].subImage.imageArrayIndex = 0;
1653 m_projectionLayerViews[i].pose = m_views[i].pose;
1654 m_projectionLayerViews[i].fov = m_views[i].fov;
1656 updateCameraNonMultiview(i, m_projectionLayerViews[i]);
1658 doRender(m_projectionLayerViews[i].subImage,
1660 depthSwapchainImage);
1662 if (depthSwapchainImage) {
1663 m_layerDepthInfos[i].subImage.swapchain = m_depthSwapchains[i].handle;
1664 m_layerDepthInfos[i].subImage.imageArrayIndex = 0;
1665 m_layerDepthInfos[i].minDepth = 0;
1666 m_layerDepthInfos[i].maxDepth = 1;
1667 QQuick3DXrEyeCamera *cam = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
1668 m_layerDepthInfos[i].nearZ = cam ? cam->clipNear() : 1.0f;
1669 m_layerDepthInfos[i].farZ = cam ? cam->clipFar() : 10000.0f;
1670 m_projectionLayerViews[i].next = &m_layerDepthInfos[i];
1672 m_projectionLayerViews[i].next =
nullptr;
1675 XrSwapchainImageReleaseInfo releaseInfo{};
1676 releaseInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
1677 if (!checkXrResult(xrReleaseSwapchainImage(viewSwapchain.handle, &releaseInfo)))
1678 qWarning(
"Failed to release swapchain image");
1679 if (depthSwapchainImage) {
1680 if (!checkXrResult(xrReleaseSwapchainImage(m_depthSwapchains[i].handle, &releaseInfo)))
1681 qWarning(
"Failed to release depth swapchain image");
1686#if QT_CONFIG(graphicsframecapture)
1688 m_frameCapture->endCaptureFrame();
1691 layer.space = m_appSpace;
1692 layer.viewCount = (uint32_t)m_projectionLayerViews.size();
1693 layer.views = m_projectionLayerViews.data();
1697 qCDebug(lcQuick3DXr,
"xrLocateViews returned qualified success code: %s", to_string(res));
1702 const XrSwapchainImageBaseHeader *swapchainImage,
1703 const XrSwapchainImageBaseHeader *depthSwapchainImage)
1705 Q_Q(QQuick3DXrManager);
1707 auto *quickWindow = q->m_quickWindow;
1708 auto *renderControl = q->m_renderControl;
1710 const int arraySize = m_multiviewRendering ? m_swapchains[0].arraySize : 1;
1711 quickWindow->setRenderTarget(m_graphics->renderTarget(subImage,
1713 m_colorSwapchainFormat,
1716 depthSwapchainImage,
1717 m_depthSwapchainFormat));
1719 quickWindow->setGeometry(0,
1721 subImage.imageRect.extent.width,
1722 subImage.imageRect.extent.height);
1723 quickWindow->contentItem()->setSize(QSizeF(subImage.imageRect.extent.width,
1724 subImage.imageRect.extent.height));
1726 renderControl->polishItems();
1727 renderControl->beginFrame();
1728 renderControl->sync();
1729 renderControl->render();
1730 renderControl->endFrame();
1735 QRhiRenderTarget *rt = QQuickWindowPrivate::get(quickWindow)->activeCustomRhiRenderTarget();
1736 if (rt->resourceType() == QRhiResource::TextureRenderTarget &&
static_cast<QRhiTextureRenderTarget *>(rt)->description().colorAttachmentAt(0)->texture())
1737 emit q->frameReady();
1742 PFN_xrEnumerateColorSpacesFB pfnxrEnumerateColorSpacesFB = NULL;
1743 OpenXRHelpers::resolveXrFunction(m_instance,
"xrEnumerateColorSpacesFB", (PFN_xrVoidFunction*)(&pfnxrEnumerateColorSpacesFB));
1744 if (!pfnxrEnumerateColorSpacesFB)
1747 uint32_t colorSpaceCountOutput = 0;
1748 if (!checkXrResult(pfnxrEnumerateColorSpacesFB(m_session, 0, &colorSpaceCountOutput,
nullptr))) {
1749 qWarning(
"Failed to enumerate color spaces");
1753 XrColorSpaceFB* colorSpaces =
1754 (XrColorSpaceFB*)malloc(colorSpaceCountOutput *
sizeof(XrColorSpaceFB));
1756 if (!checkXrResult(pfnxrEnumerateColorSpacesFB(m_session, colorSpaceCountOutput, &colorSpaceCountOutput, colorSpaces))) {
1757 qWarning(
"Failed to enumerate color spaces");
1761 qCDebug(lcQuick3DXr,
"Supported color spaces:");
1762 for (uint32_t i = 0; i < colorSpaceCountOutput; i++) {
1763 qCDebug(lcQuick3DXr,
"%d:%d", i, colorSpaces[i]);
1766 const XrColorSpaceFB requestColorSpace = XR_COLOR_SPACE_QUEST_FB;
1768 PFN_xrSetColorSpaceFB pfnxrSetColorSpaceFB = NULL;
1769 OpenXRHelpers::resolveXrFunction(m_instance,
"xrSetColorSpaceFB", (PFN_xrVoidFunction*)(&pfnxrSetColorSpaceFB));
1771 if (!checkXrResult(pfnxrSetColorSpaceFB(m_session, requestColorSpace)))
1772 qWarning(
"Failed to set color space");
1779 PFN_xrEnumerateDisplayRefreshRatesFB pfnxrEnumerateDisplayRefreshRatesFB = NULL;
1780 OpenXRHelpers::resolveXrFunction(m_instance,
"xrEnumerateDisplayRefreshRatesFB", (PFN_xrVoidFunction*)(&pfnxrEnumerateDisplayRefreshRatesFB));
1781 if (!pfnxrEnumerateDisplayRefreshRatesFB)
1784 uint32_t numSupportedDisplayRefreshRates;
1785 QVector<
float> supportedDisplayRefreshRates;
1787 if (!checkXrResult(pfnxrEnumerateDisplayRefreshRatesFB(m_session, 0, &numSupportedDisplayRefreshRates,
nullptr))) {
1788 qWarning(
"Failed to enumerate display refresh rates");
1792 supportedDisplayRefreshRates.resize(numSupportedDisplayRefreshRates);
1794 if (!checkXrResult(pfnxrEnumerateDisplayRefreshRatesFB(
1796 numSupportedDisplayRefreshRates,
1797 &numSupportedDisplayRefreshRates,
1798 supportedDisplayRefreshRates.data())))
1800 qWarning(
"Failed to enumerate display refresh rates");
1804 qCDebug(lcQuick3DXr,
"Supported Refresh Rates:");
1805 for (uint32_t i = 0; i < numSupportedDisplayRefreshRates; i++) {
1806 qCDebug(lcQuick3DXr,
"%d:%f", i, supportedDisplayRefreshRates[i]);
1809 PFN_xrGetDisplayRefreshRateFB pfnGetDisplayRefreshRate;
1810 OpenXRHelpers::resolveXrFunction(m_instance,
"xrGetDisplayRefreshRateFB", (PFN_xrVoidFunction*)(&pfnGetDisplayRefreshRate));
1812 float currentDisplayRefreshRate = 0.0f;
1813 if (!checkXrResult(pfnGetDisplayRefreshRate(m_session, ¤tDisplayRefreshRate)))
1814 qWarning(
"Failed to get display refresh rate");
1816 qCDebug(lcQuick3DXr,
"Current System Display Refresh Rate: %f", currentDisplayRefreshRate);
1818 PFN_xrRequestDisplayRefreshRateFB pfnRequestDisplayRefreshRate;
1819 OpenXRHelpers::resolveXrFunction(m_instance,
"xrRequestDisplayRefreshRateFB", (PFN_xrVoidFunction*)(&pfnRequestDisplayRefreshRate));
1822 if (!checkXrResult(pfnRequestDisplayRefreshRate(m_session, 0.0f)))
1823 qWarning(
"Failed to request display refresh rate");
1825 qCDebug(lcQuick3DXr,
"Requesting system default display refresh rate");
1830 PFN_xrCreateFoveationProfileFB pfnCreateFoveationProfileFB;
1831 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnCreateFoveationProfileFB));
1832 if (!pfnCreateFoveationProfileFB)
1835 PFN_xrDestroyFoveationProfileFB pfnDestroyFoveationProfileFB;
1836 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnDestroyFoveationProfileFB));
1838 PFN_xrUpdateSwapchainFB pfnUpdateSwapchainFB;
1839 OpenXRHelpers::resolveXrFunction(m_instance,
"xrUpdateSwapchainFB", (PFN_xrVoidFunction*)(&pfnUpdateSwapchainFB));
1841 for (
auto swapchain : m_swapchains) {
1842 XrFoveationLevelProfileCreateInfoFB levelProfileCreateInfo = {};
1843 levelProfileCreateInfo.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
1844 levelProfileCreateInfo.level = m_foveationLevel;
1845 levelProfileCreateInfo.verticalOffset = 0;
1846 levelProfileCreateInfo.dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;
1848 XrFoveationProfileCreateInfoFB profileCreateInfo = {};
1849 profileCreateInfo.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
1850 profileCreateInfo.next = &levelProfileCreateInfo;
1852 XrFoveationProfileFB foveationProfile;
1853 pfnCreateFoveationProfileFB(m_session, &profileCreateInfo, &foveationProfile);
1855 XrSwapchainStateFoveationFB foveationUpdateState = {};
1856 memset(&foveationUpdateState, 0,
sizeof(foveationUpdateState));
1857 foveationUpdateState.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
1858 foveationUpdateState.profile = foveationProfile;
1860 XrResult updateSwapchainFBResult = OpenXRHelpers::safeCall(pfnUpdateSwapchainFB, swapchain.handle, (
const XrSwapchainStateBaseHeaderFB*)(&foveationUpdateState));
1861 if (updateSwapchainFBResult == XR_ERROR_FUNCTION_UNSUPPORTED)
1864 XrResult destroyFoveationProfileFBResult = OpenXRHelpers::safeCall(pfnDestroyFoveationProfileFB, foveationProfile);
1865 if (destroyFoveationProfileFBResult == XR_ERROR_FUNCTION_UNSUPPORTED)
1868 qCDebug(lcQuick3DXr,
"Fixed foveated rendering requested with level %d",
int(m_foveationLevel));
1877 Q_ASSERT(m_passthroughSupported && m_enablePassthrough);
1879 PFN_xrCreatePassthroughFB pfnXrCreatePassthroughFBX =
nullptr;
1880 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreatePassthroughFB", (PFN_xrVoidFunction*)(&pfnXrCreatePassthroughFBX));
1882 XrPassthroughCreateInfoFB passthroughCreateInfo{};
1883 passthroughCreateInfo.type = XR_TYPE_PASSTHROUGH_CREATE_INFO_FB;
1884 passthroughCreateInfo.flags = XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB;
1886 XrResult xrCreatePassthroughFBXResult = OpenXRHelpers::safeCall(pfnXrCreatePassthroughFBX, m_session,
static_cast<
const XrPassthroughCreateInfoFB*>(&passthroughCreateInfo), &m_passthroughFeature);
1887 if (!checkXrResult(xrCreatePassthroughFBXResult))
1888 qWarning(
"Failed to create passthrough object");
1893 PFN_xrDestroyPassthroughFB pfnXrDestroyPassthroughFBX =
nullptr;
1894 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyPassthroughFB", (PFN_xrVoidFunction*)(&pfnXrDestroyPassthroughFBX));
1896 XrResult xrDestroyPassthroughFBXResult = OpenXRHelpers::safeCall(pfnXrDestroyPassthroughFBX, m_passthroughFeature);
1897 if (!checkXrResult(xrDestroyPassthroughFBXResult))
1898 qWarning(
"Failed to destroy passthrough object");
1900 m_passthroughFeature = XR_NULL_HANDLE;
1905 PFN_xrPassthroughStartFB pfnXrPassthroughStartFBX =
nullptr;
1906 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughStartFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughStartFBX));
1908 XrResult xrPassthroughStartFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughStartFBX, m_passthroughFeature);
1909 if (!checkXrResult(xrPassthroughStartFBXResult))
1910 qWarning(
"Failed to start passthrough");
1915 PFN_xrPassthroughPauseFB pfnXrPassthroughPauseFBX =
nullptr;
1916 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughPauseFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughPauseFBX));
1918 XrResult xrPassthroughPauseFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughPauseFBX, m_passthroughFeature);
1919 if (!checkXrResult(xrPassthroughPauseFBXResult))
1920 qWarning(
"Failed to pause passthrough");
1925 PFN_xrCreatePassthroughLayerFB pfnXrCreatePassthroughLayerFBX =
nullptr;
1926 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreatePassthroughLayerFB", (PFN_xrVoidFunction*)(&pfnXrCreatePassthroughLayerFBX));
1928 XrPassthroughLayerCreateInfoFB layerCreateInfo{};
1929 layerCreateInfo.type = XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB;
1930 layerCreateInfo.passthrough = m_passthroughFeature;
1931 layerCreateInfo.purpose = XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB;
1932 if (m_enablePassthrough)
1933 layerCreateInfo.flags = XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB;
1935 XrResult xrCreatePassthroughLayerFBXResult = OpenXRHelpers::safeCall(pfnXrCreatePassthroughLayerFBX, m_session,
static_cast<
const XrPassthroughLayerCreateInfoFB*>(&layerCreateInfo), &m_passthroughLayer);
1936 if (!checkXrResult(xrCreatePassthroughLayerFBXResult))
1937 qWarning(
"Failed to create passthrough layer");
1942 PFN_xrDestroyPassthroughLayerFB pfnXrDestroyPassthroughLayerFBX =
nullptr;
1943 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyPassthroughLayerFB", (PFN_xrVoidFunction*)(&pfnXrDestroyPassthroughLayerFBX));
1945 XrResult xrDestroyPassthroughLayerFBXResult = OpenXRHelpers::safeCall(pfnXrDestroyPassthroughLayerFBX, m_passthroughLayer);
1946 if (!checkXrResult(xrDestroyPassthroughLayerFBXResult))
1947 qWarning(
"Failed to destroy passthrough layer");
1949 m_passthroughLayer = XR_NULL_HANDLE;
1954 PFN_xrPassthroughLayerPauseFB pfnXrPassthroughLayerPauseFBX =
nullptr;
1955 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughLayerPauseFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughLayerPauseFBX));
1957 XrResult xrPassthroughLayerPauseFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughLayerPauseFBX, m_passthroughLayer);
1958 if (!checkXrResult(xrPassthroughLayerPauseFBXResult))
1959 qWarning(
"Failed to pause passthrough layer");
1964 PFN_xrPassthroughLayerResumeFB pfnXrPassthroughLayerResumeFBX =
nullptr;
1965 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughLayerResumeFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughLayerResumeFBX));
1967 XrResult xrPassthroughLayerResumeFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughLayerResumeFBX, m_passthroughLayer);
1968 if (!checkXrResult(xrPassthroughLayerResumeFBXResult))
1969 qWarning(
"Failed to resume passthrough layer");
1974 quint32 instanceExtensionCount;
1975 if (!checkXrResult(xrEnumerateInstanceExtensionProperties(layerName, 0, &instanceExtensionCount,
nullptr))) {
1976 qWarning(
"Failed to enumerate instance extension properties");
1980 QVector<XrExtensionProperties> extensions(instanceExtensionCount);
1981 for (XrExtensionProperties& extension : extensions) {
1982 extension.type = XR_TYPE_EXTENSION_PROPERTIES;
1983 extension.next =
nullptr;
1986 if (!checkXrResult(xrEnumerateInstanceExtensionProperties(layerName,
1987 quint32(extensions.size()),
1988 &instanceExtensionCount,
1989 extensions.data())))
1991 qWarning(
"Failed to enumerate instance extension properties");
1994 const QByteArray indentStr(indent,
' ');
1995 qCDebug(lcQuick3DXr,
"%sAvailable Extensions: (%d)", indentStr.data(), instanceExtensionCount);
1996 for (
const XrExtensionProperties& extension : extensions) {
1997 qCDebug(lcQuick3DXr,
"%s Name=%s Version=%d.%d.%d",
1999 extension.extensionName,
2000 XR_VERSION_MAJOR(extension.extensionVersion),
2001 XR_VERSION_MINOR(extension.extensionVersion),
2002 XR_VERSION_PATCH(extension.extensionVersion));
2009 if (!checkXrResult(xrEnumerateApiLayerProperties(0, &layerCount,
nullptr))) {
2010 qWarning(
"Failed to enumerate API layer properties");
2014 QVector<XrApiLayerProperties> layers(layerCount);
2015 for (XrApiLayerProperties& layer : layers) {
2016 layer.type = XR_TYPE_API_LAYER_PROPERTIES;
2017 layer.next =
nullptr;
2020 if (!checkXrResult(xrEnumerateApiLayerProperties(quint32(layers.size()), &layerCount, layers.data()))) {
2021 qWarning(
"Failed to enumerate API layer properties");
2025 qCDebug(lcQuick3DXr,
"Available Layers: (%d)", layerCount);
2026 for (
const XrApiLayerProperties& layer : layers) {
2027 qCDebug(lcQuick3DXr,
" Name=%s SpecVersion=%d.%d.%d LayerVersion=%d.%d.%d Description=%s",
2029 XR_VERSION_MAJOR(layer.specVersion),
2030 XR_VERSION_MINOR(layer.specVersion),
2031 XR_VERSION_PATCH(layer.specVersion),
2032 XR_VERSION_MAJOR(layer.layerVersion),
2033 XR_VERSION_MINOR(layer.layerVersion),
2034 XR_VERSION_PATCH(layer.layerVersion),
2036 checkXrExtensions(layer.layerName, 4);
2043 XrApplicationInfo appInfo;
2044 strcpy(appInfo.applicationName, QCoreApplication::applicationName().toUtf8());
2045 appInfo.applicationVersion = 7;
2046 strcpy(appInfo.engineName, QStringLiteral(
"Qt").toUtf8());
2047 appInfo.engineVersion = 6;
2052 appInfo.apiVersion = XR_MAKE_VERSION(1, 0, 34);
2055 uint32_t apiLayerCount = 0;
2056 xrEnumerateApiLayerProperties(0, &apiLayerCount,
nullptr);
2057 QVector<XrApiLayerProperties> apiLayerProperties(apiLayerCount);
2058 for (uint32_t i = 0; i < apiLayerCount; i++) {
2059 apiLayerProperties[i].type = XR_TYPE_API_LAYER_PROPERTIES;
2060 apiLayerProperties[i].next =
nullptr;
2062 xrEnumerateApiLayerProperties(apiLayerCount, &apiLayerCount, apiLayerProperties.data());
2065 QVector<
const char*> enabledApiLayers;
2070 const bool wantsValidationLayer = qEnvironmentVariableIntValue(
"QSG_RHI_DEBUG_LAYER");
2071 if (wantsValidationLayer) {
2072 if (isApiLayerSupported(
"XR_APILAYER_LUNARG_core_validation", apiLayerProperties))
2073 enabledApiLayers.append(
"XR_APILAYER_LUNARG_core_validation");
2075 qCDebug(lcQuick3DXr,
"OpenXR validation layer requested, but not available");
2078 qCDebug(lcQuick3DXr) <<
"Requesting to enable XR API layers:" << enabledApiLayers;
2080 m_enabledApiLayers.clear();
2081 for (
const char *layer : enabledApiLayers)
2082 m_enabledApiLayers.append(QString::fromLatin1(layer));
2085 uint32_t extensionCount = 0;
2086 xrEnumerateInstanceExtensionProperties(
nullptr, 0, &extensionCount,
nullptr);
2087 QVector<XrExtensionProperties> extensionProperties(extensionCount);
2088 for (uint32_t i = 0; i < extensionCount; i++) {
2091 extensionProperties[i].type = XR_TYPE_EXTENSION_PROPERTIES;
2092 extensionProperties[i].next =
nullptr;
2094 xrEnumerateInstanceExtensionProperties(
nullptr, extensionCount, &extensionCount, extensionProperties.data());
2096 QVector<
const char*> enabledExtensions;
2097 if (!m_graphics->initialize(extensionProperties)) {
2098 qWarning(
"Failed to initialize OpenXR graphics module");
2099 return XR_ERROR_GRAPHICS_DEVICE_INVALID;
2101 enabledExtensions.append(m_graphics->getRequiredExtensions());
2103 if (isExtensionSupported(
"XR_EXT_debug_utils", extensionProperties))
2104 enabledExtensions.append(
"XR_EXT_debug_utils");
2106 if (isExtensionSupported(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME, extensionProperties))
2107 enabledExtensions.append(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME);
2109 m_handtrackingExtensionSupported = isExtensionSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME, extensionProperties);
2110 if (m_handtrackingExtensionSupported)
2111 enabledExtensions.append(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
2113 m_compositionLayerDepthSupported = isExtensionSupported(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME, extensionProperties);
2114 if (m_compositionLayerDepthSupported) {
2117 enabledExtensions.append(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
2118 m_submitLayerDepth = qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_SUBMIT_DEPTH");
2119 if (m_submitLayerDepth)
2120 qCDebug(lcQuick3DXr,
"submitLayerDepth defaults to true due to env.var.");
2122 m_submitLayerDepth =
false;
2127 m_handtrackingAimExtensionSupported = isExtensionSupported(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME, extensionProperties);
2128 if (m_handtrackingAimExtensionSupported)
2129 enabledExtensions.append(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
2131 if (isExtensionSupported(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME, extensionProperties))
2132 enabledExtensions.append(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME);
2134 if (isExtensionSupported(XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME, extensionProperties))
2135 enabledExtensions.append(XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME);
2139 uint32_t passthroughSpecVersion = 0;
2140 if (isExtensionSupported(XR_FB_PASSTHROUGH_EXTENSION_NAME, extensionProperties, &passthroughSpecVersion)) {
2141 qCDebug(lcQuick3DXr,
"Passthrough extension is supported, spec version %u", passthroughSpecVersion);
2142 enabledExtensions.append(XR_FB_PASSTHROUGH_EXTENSION_NAME);
2144 qCDebug(lcQuick3DXr,
"Passthrough extension is NOT supported");
2147 if (isExtensionSupported(XR_FB_TRIANGLE_MESH_EXTENSION_NAME, extensionProperties))
2148 enabledExtensions.append(XR_FB_TRIANGLE_MESH_EXTENSION_NAME);
2150 m_displayRefreshRateExtensionSupported = isExtensionSupported(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME, extensionProperties);
2151 if (m_displayRefreshRateExtensionSupported)
2152 enabledExtensions.append(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME);
2154 m_colorspaceExtensionSupported = isExtensionSupported(XR_FB_COLOR_SPACE_EXTENSION_NAME, extensionProperties);
2155 if (m_colorspaceExtensionSupported)
2156 enabledExtensions.append(XR_FB_COLOR_SPACE_EXTENSION_NAME);
2158 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME, extensionProperties))
2159 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME);
2161 m_foveationExtensionSupported = isExtensionSupported(XR_FB_FOVEATION_EXTENSION_NAME, extensionProperties);
2162 if (m_foveationExtensionSupported)
2163 enabledExtensions.append(XR_FB_FOVEATION_EXTENSION_NAME);
2165 if (isExtensionSupported(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME, extensionProperties))
2166 enabledExtensions.append(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME);
2168 if (m_spaceExtension) {
2169 const auto requiredExtensions = m_spaceExtension->requiredExtensions();
2170 bool isSupported =
true;
2171 for (
const auto extension : requiredExtensions) {
2172 isSupported = isExtensionSupported(extension, extensionProperties) && isSupported;
2176 m_spaceExtensionSupported = isSupported;
2178 enabledExtensions.append(requiredExtensions);
2182 if (isExtensionSupported(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME, extensionProperties))
2183 enabledExtensions.append(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME);
2185 m_androidCreateInstanceExtensionSupported = isExtensionSupported(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME, extensionProperties);
2186 if (m_androidCreateInstanceExtensionSupported)
2187 enabledExtensions.append(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME);
2189 auto graphicsAPI = QQuickWindow::graphicsApi();
2190 if (graphicsAPI == QSGRendererInterface::Vulkan) {
2191 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME, extensionProperties))
2192 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME);
2193 }
else if (graphicsAPI == QSGRendererInterface::OpenGL) {
2194 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME, extensionProperties))
2195 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME);
2199 qCDebug(lcQuick3DXr) <<
"Requesting to enable XR extensions:" << enabledExtensions;
2201 m_enabledExtensions.clear();
2202 for (
const char *extension : enabledExtensions)
2203 m_enabledExtensions.append(QString::fromLatin1(extension));
2206 XrInstanceCreateInfo xrInstanceInfo{};
2207 xrInstanceInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
2210 XrInstanceCreateInfoAndroidKHR xrInstanceCreateInfoAndroid {};
2211 if (m_androidCreateInstanceExtensionSupported) {
2212 xrInstanceCreateInfoAndroid.type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR;
2213 xrInstanceCreateInfoAndroid.applicationVM = m_javaVM;
2214 xrInstanceCreateInfoAndroid.applicationActivity = m_androidActivity.object();
2216 xrInstanceInfo.next = &xrInstanceCreateInfoAndroid;
2221 xrInstanceInfo.createFlags = 0;
2222 xrInstanceInfo.applicationInfo = appInfo;
2223 xrInstanceInfo.enabledApiLayerCount = enabledApiLayers.count();
2224 xrInstanceInfo.enabledApiLayerNames = enabledApiLayers.constData();
2225 xrInstanceInfo.enabledExtensionCount = enabledExtensions.count();
2226 xrInstanceInfo.enabledExtensionNames = enabledExtensions.constData();
2228 return xrCreateInstance(&xrInstanceInfo, &m_instance);
2233 Q_ASSERT(m_instance != XR_NULL_HANDLE);
2234 XrInstanceProperties instanceProperties{};
2235 instanceProperties.type = XR_TYPE_INSTANCE_PROPERTIES;
2236 if (!checkXrResult(xrGetInstanceProperties(m_instance, &instanceProperties))) {
2237 qWarning(
"Failed to get instance properties");
2241 m_runtimeName = QString::fromUtf8(instanceProperties.runtimeName);
2242 m_runtimeVersion = QVersionNumber(XR_VERSION_MAJOR(instanceProperties.runtimeVersion),
2243 XR_VERSION_MINOR(instanceProperties.runtimeVersion),
2244 XR_VERSION_PATCH(instanceProperties.runtimeVersion));
2246 qCDebug(lcQuick3DXr,
"Instance RuntimeName=%s RuntimeVersion=%d.%d.%d",
2247 qPrintable(m_runtimeName),
2248 m_runtimeVersion.majorVersion(),
2249 m_runtimeVersion.minorVersion(),
2250 m_runtimeVersion.microVersion());
2255 if (!m_enabledExtensions.contains(QString::fromUtf8(
"XR_EXT_debug_utils"))) {
2256 qCDebug(lcQuick3DXr,
"No debug utils extension, message redirection not set up");
2260#ifdef XR_EXT_debug_utils
2261 PFN_xrCreateDebugUtilsMessengerEXT xrCreateDebugUtilsMessengerEXT =
nullptr;
2262 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreateDebugUtilsMessengerEXT",
reinterpret_cast<PFN_xrVoidFunction *>(&xrCreateDebugUtilsMessengerEXT));
2263 if (!xrCreateDebugUtilsMessengerEXT)
2266 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyDebugUtilsMessengerEXT",
reinterpret_cast<PFN_xrVoidFunction *>(&m_xrDestroyDebugUtilsMessengerEXT));
2268 XrDebugUtilsMessengerCreateInfoEXT messengerInfo = {};
2269 messengerInfo.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
2270 messengerInfo.messageSeverities = XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
2271 | XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
2272 messengerInfo.messageTypes = XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
2273 | XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
2274 | XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
2275 | XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT;
2276 messengerInfo.userCallback = defaultDebugCallbackFunc;
2277 messengerInfo.userData =
this;
2279 XrResult err = xrCreateDebugUtilsMessengerEXT(m_instance, &messengerInfo, &m_debugMessenger);
2280 if (!checkXrResult(err))
2281 qWarning(
"Quick 3D XR: Failed to create debug report callback, OpenXR messages will not get redirected (%d)", err);
2287 Q_ASSERT(m_instance != XR_NULL_HANDLE);
2288 Q_ASSERT(m_systemId == XR_NULL_SYSTEM_ID);
2290 XrSystemGetInfo hmdInfo{};
2291 hmdInfo.type = XR_TYPE_SYSTEM_GET_INFO;
2292 hmdInfo.next =
nullptr;
2293 hmdInfo.formFactor = m_formFactor;
2295 const XrResult result = xrGetSystem(m_instance, &hmdInfo, &m_systemId);
2296 const bool success = checkXrResult(result);
2302 checkViewConfiguration();
2309 quint32 viewConfigTypeCount;
2310 if (!checkXrResult(xrEnumerateViewConfigurations(m_instance,
2313 &viewConfigTypeCount,
2316 qWarning(
"Failed to enumerate view configurations");
2319 QVector<XrViewConfigurationType> viewConfigTypes(viewConfigTypeCount);
2320 if (!checkXrResult(xrEnumerateViewConfigurations(m_instance,
2322 viewConfigTypeCount,
2323 &viewConfigTypeCount,
2324 viewConfigTypes.data())))
2326 qWarning(
"Failed to enumerate view configurations");
2330 qCDebug(lcQuick3DXr,
"Available View Configuration Types: (%d)", viewConfigTypeCount);
2331 for (XrViewConfigurationType viewConfigType : viewConfigTypes) {
2332 qCDebug(lcQuick3DXr,
" View Configuration Type: %s %s", to_string(viewConfigType), viewConfigType == m_viewConfigType ?
"(Selected)" :
"");
2333 XrViewConfigurationProperties viewConfigProperties{};
2334 viewConfigProperties.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
2335 if (!checkXrResult(xrGetViewConfigurationProperties(m_instance,
2338 &viewConfigProperties)))
2340 qWarning(
"Failed to get view configuration properties");
2344 qCDebug(lcQuick3DXr,
" View configuration FovMutable=%s", viewConfigProperties.fovMutable == XR_TRUE ?
"True" :
"False");
2347 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
2354 qWarning(
"Failed to enumerate configuration views");
2358 if (viewCount > 0) {
2359 QVector<XrViewConfigurationView> views(viewCount, {XR_TYPE_VIEW_CONFIGURATION_VIEW,
nullptr, 0, 0, 0, 0, 0, 0});
2360 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
2367 qWarning(
"Failed to enumerate configuration views");
2371 for (
int i = 0; i < views.size(); ++i) {
2372 const XrViewConfigurationView& view = views[i];
2373 qCDebug(lcQuick3DXr,
" View [%d]: Recommended Width=%d Height=%d SampleCount=%d",
2375 view.recommendedImageRectWidth,
2376 view.recommendedImageRectHeight,
2377 view.recommendedSwapchainSampleCount);
2378 qCDebug(lcQuick3DXr,
" View [%d]: Maximum Width=%d Height=%d SampleCount=%d",
2380 view.maxImageRectWidth,
2381 view.maxImageRectHeight,
2382 view.maxSwapchainSampleCount);
2385 qCDebug(lcQuick3DXr,
"Empty view configuration type");
2387 checkEnvironmentBlendMode(viewConfigType);
2393 return OpenXRHelpers::checkXrResult(result, m_instance);
2399 if (!checkXrResult(xrEnumerateEnvironmentBlendModes(m_instance,
2406 qWarning(
"Failed to enumerate blend modes");
2410 qCDebug(lcQuick3DXr,
"Available Environment Blend Mode count : (%d)", count);
2412 QVector<XrEnvironmentBlendMode> blendModes(count);
2413 if (!checkXrResult(xrEnumerateEnvironmentBlendModes(m_instance,
2418 blendModes.data())))
2420 qWarning(
"Failed to enumerate blend modes");
2424 bool blendModeFound =
false;
2425 for (XrEnvironmentBlendMode mode : blendModes) {
2426 const bool blendModeMatch = (mode == m_environmentBlendMode);
2427 qCDebug(lcQuick3DXr,
"Environment Blend Mode (%s) : %s", to_string(mode), blendModeMatch ?
"(Selected)" :
"");
2428 blendModeFound |= blendModeMatch;
2430 if (!blendModeFound)
2431 qWarning(
"No matching environment blend mode found");
2436#include "qquick3dxrmanager_openxr.moc"
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
void startWaitingForFrame()
static constexpr QEvent::Type asQEvent(QQuick3DOpenXRThreadWorker::Event event)
QQuick3DXrManagerPrivate(QQuick3DXrManager &manager)
void setupWindow(QQuickWindow *window)
bool finalizeGraphics(QRhi *rhi)
QVersionNumber runtimeVersion() const
QtQuick3DXr::ReferenceSpace getReferenceSpace() const
QStringList enabledExtensions() const
~QQuick3DXrManagerPrivate()
bool supportsPassthrough() const
bool setupGraphics(QQuickWindow *window)
void setMultiViewRenderingEnabled(bool enable)
void setDepthSubmissionEnabled(bool enable)
void setSamples(int samples)
void getDefaultClipDistances(float &nearClip, float &farClip) const
bool isGraphicsInitialized() const
bool setPassthroughEnabled(bool enable)
QString runtimeName() const
static bool isMultiviewRenderingDisabled()
@ ReferenceSpaceLocalFloor
QT_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(lcEventDispatcher)
#define MAKE_TO_STRING_FUNC(enumType)
static bool isApiLayerSupported(const char *layerName, const QVector< XrApiLayerProperties > &apiLayerProperties)
#define ENUM_CASE_STR(name, val)
static const char s_workerThreadName[]
static QtQuick3DXr::ReferenceSpace getReferenceSpaceType(XrReferenceSpaceType referenceSpace)
static std::pair< XrResult, XrFrameState > waitForNextFrame(XrSession session)
static bool isExtensionSupported(const char *extensionName, const QVector< XrExtensionProperties > &instanceExtensionProperties, uint32_t *extensionVersion=nullptr)