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);
149 m_errorString = QObject::tr(
"%1 for runtime %2 %3 failed with %4.")
150 .arg(QLatin1StringView(callName),
152 m_runtimeVersion.toString(),
153 OpenXRHelpers::getXrResultAsString(result, m_instance));
154 if (result == XR_ERROR_FORM_FACTOR_UNAVAILABLE)
155 m_errorString += QObject::tr(
"\nThe OpenXR runtime has no connection to the headset; check if connection is active and functional.");
171 QSSG_ASSERT(manager !=
nullptr,
return nullptr);
172 return manager->d_func();
175void QQuick3DXrManagerPrivate::updateCameraHelper(QQuick3DXrEyeCamera *camera,
const XrCompositionLayerProjectionView &layerView)
177 camera->setLeftTangent(qTan(layerView.fov.angleLeft));
178 camera->setRightTangent(qTan(layerView.fov.angleRight));
179 camera->setUpTangent(qTan(layerView.fov.angleUp));
180 camera->setDownTangent(qTan(layerView.fov.angleDown));
182 camera->setPosition(QVector3D(layerView.pose.position.x,
183 layerView.pose.position.y,
184 layerView.pose.position.z) * 100.0f);
186 camera->setRotation(QQuaternion(layerView.pose.orientation.w,
187 layerView.pose.orientation.x,
188 layerView.pose.orientation.y,
189 layerView.pose.orientation.z));
196 Q_Q(QQuick3DXrManager);
198 QQuick3DXrOrigin *xrOrigin = q->m_xrOrigin;
200 QQuick3DXrEyeCamera *eyeCamera = xrOrigin ? xrOrigin->eyeCamera(eye) :
nullptr;
203 updateCameraHelper(eyeCamera, layerView);
205 q->m_vrViewport->setCamera(eyeCamera);
211 Q_Q(QQuick3DXrManager);
213 QQuick3DXrOrigin *xrOrigin = q->m_xrOrigin;
214 QQuick3DViewport *vrViewport = q->m_vrViewport;
216 QVarLengthArray<QQuick3DCamera *, 4> cameras;
217 for (
int i = projectionLayerViewStartIndex; i < projectionLayerViewStartIndex + count; ++i) {
218 QQuick3DXrEyeCamera *eyeCamera = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
220 updateCameraHelper(eyeCamera, m_projectionLayerViews[i]);
221 cameras.append(eyeCamera);
223 vrViewport->setMultiViewCameras(cameras.data(), cameras.count());
228 bool supported =
false;
229 XrSystemPassthroughProperties2FB passthroughSystemProperties{};
230 passthroughSystemProperties.type = XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES2_FB;
232 XrSystemProperties systemProperties{};
233 systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
234 systemProperties.next = &passthroughSystemProperties;
236 XrSystemGetInfo systemGetInfo{};
237 systemGetInfo.type = XR_TYPE_SYSTEM_GET_INFO;
238 systemGetInfo.formFactor = m_formFactor;
240 XrSystemId systemId = XR_NULL_SYSTEM_ID;
241 xrGetSystem(m_instance, &systemGetInfo, &systemId);
242 xrGetSystemProperties(m_instance, systemId, &systemProperties);
244 supported = (passthroughSystemProperties.capabilities & XR_PASSTHROUGH_CAPABILITY_BIT_FB) == XR_PASSTHROUGH_CAPABILITY_BIT_FB;
250 XrSystemPassthroughPropertiesFB oldPassthroughSystemProperties{};
251 oldPassthroughSystemProperties.type = XR_TYPE_SYSTEM_PASSTHROUGH_PROPERTIES_FB;
252 systemProperties.next = &oldPassthroughSystemProperties;
253 xrGetSystemProperties(m_instance, systemId, &systemProperties);
254 supported = oldPassthroughSystemProperties.supportsPassthrough;
262 QSSG_ASSERT(window !=
nullptr,
return);
264 m_graphics->setupWindow(window);
269 return m_graphics && m_graphics->rhi();
274 QSSG_ASSERT(window !=
nullptr,
return false);
275 QSSG_ASSERT(m_graphics !=
nullptr,
return false);
277 return m_graphics->setupGraphics(m_instance, m_systemId, window->graphicsConfiguration());
282 Q_Q(QQuick3DXrManager);
283 QCoreApplication::postEvent(q,
new QEvent(QEvent::UpdateRequest));
288 Q_Q(QQuick3DXrManager);
290 bool exitRenderLoop =
false;
291 bool requestrestart =
false;
292 pollEvents(&exitRenderLoop, &requestrestart);
295 emit q->sessionEnded();
297 if (m_sessionRunning && m_inputManager) {
298 QQuick3DXrInputManagerPrivate::get(m_inputManager)->pollActions();
305 for (
const Swapchain &swapchain : m_swapchains)
306 xrDestroySwapchain(swapchain.handle);
308 m_swapchains.clear();
309 m_swapchainImages.clear();
310 m_configViews.clear();
312 for (
const Swapchain &swapchain : m_depthSwapchains)
313 xrDestroySwapchain(swapchain.handle);
315 m_depthSwapchains.clear();
316 m_depthSwapchainImages.clear();
321 Q_ASSERT(m_session != XR_NULL_HANDLE);
323 XrFrameWaitInfo frameWaitInfo{};
324 frameWaitInfo.type = XR_TYPE_FRAME_WAIT_INFO;
325 XrFrameState frameState{};
326 frameState.type = XR_TYPE_FRAME_STATE;
327 if (!checkXrResult(xrWaitFrame(m_session, &frameWaitInfo, &frameState))) {
328 qWarning(
"xrWaitFrame failed");
332 XrFrameBeginInfo frameBeginInfo{};
333 frameBeginInfo.type = XR_TYPE_FRAME_BEGIN_INFO;
334 if (!checkXrResult(xrBeginFrame(m_session, &frameBeginInfo))) {
335 qWarning(
"xrBeginFrame failed");
339 QVector<XrCompositionLayerBaseHeader*> layers;
341 XrCompositionLayerPassthroughFB passthroughCompLayer{};
342 passthroughCompLayer.type = XR_TYPE_COMPOSITION_LAYER_PASSTHROUGH_FB;
343 if (m_enablePassthrough && m_passthroughSupported) {
344 if (m_passthroughLayer == XR_NULL_HANDLE)
345 createMetaQuestPassthroughLayer();
346 passthroughCompLayer.layerHandle = m_passthroughLayer;
347 passthroughCompLayer.flags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
348 passthroughCompLayer.space = XR_NULL_HANDLE;
349 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*>(&passthroughCompLayer));
352 XrCompositionLayerProjection layer{};
353 layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
354 layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
355 layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
356 layer.layerFlags |= XR_COMPOSITION_LAYER_UNPREMULTIPLIED_ALPHA_BIT;
358 if (frameState.shouldRender == XR_TRUE) {
359 if (renderLayer(frameState.predictedDisplayTime, frameState.predictedDisplayPeriod, layer)) {
360 layers.push_back(
reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer));
364 XrFrameEndInfo frameEndInfo{};
365 frameEndInfo.type = XR_TYPE_FRAME_END_INFO;
366 frameEndInfo.displayTime = frameState.predictedDisplayTime;
367 if (!m_enablePassthrough)
368 frameEndInfo.environmentBlendMode = m_environmentBlendMode;
370 frameEndInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
371 frameEndInfo.layerCount = (uint32_t)layers.size();
372 frameEndInfo.layers = layers.data();
373 if (!checkXrResult(xrEndFrame(m_session, &frameEndInfo)))
374 qWarning(
"xrEndFrame failed");
379 QSSG_ASSERT(rhi !=
nullptr && m_graphics !=
nullptr,
return false);
381 if (m_multiviewRendering && !rhi->isFeatureSupported(QRhi::MultiView)) {
382 qCDebug(lcQuick3DXr) <<
"Multiview rendering is not supported with the current graphics API";
383 m_multiviewRendering =
false;
386#if QT_CONFIG(graphicsframecapture)
387 if (m_frameCapture) {
388 m_frameCapture->setCapturePath(QLatin1String(
"."));
389 m_frameCapture->setCapturePrefix(QLatin1String(
"quick3dxr"));
390 m_frameCapture->setRhi(rhi);
391 if (!m_frameCapture->isLoaded()) {
392 qWarning(
"Quick 3D XR: Frame capture was requested but QGraphicsFrameCapture is not initialized"
393 " (or has no backends enabled in the Qt build)");
395 qCDebug(lcQuick3DXr,
"Quick 3D XR: Frame capture initialized");
400 m_isGraphicsInitialized = m_graphics->finializeGraphics(rhi);
401 return m_isGraphicsInitialized;
406 Q_Q(QQuick3DXrManager);
412 if (qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_FRAME_CAPTURE")) {
413#if QT_CONFIG(graphicsframecapture)
414 m_frameCapture.reset(
new QGraphicsFrameCapture);
416 qWarning(
"Quick 3D XR: Frame capture was requested, but Qt is built without QGraphicsFrameCapture");
420#ifdef XR_USE_PLATFORM_ANDROID
422 PFN_xrInitializeLoaderKHR xrInitializeLoaderKHR;
423 xrGetInstanceProcAddr(
424 XR_NULL_HANDLE,
"xrInitializeLoaderKHR", (PFN_xrVoidFunction*)&xrInitializeLoaderKHR);
425 if (xrInitializeLoaderKHR != NULL) {
426 m_javaVM = QJniEnvironment::javaVM();
427 m_androidActivity = QNativeInterface::QAndroidApplication::context();
429 XrLoaderInitInfoAndroidKHR loaderInitializeInfoAndroid;
430 memset(&loaderInitializeInfoAndroid, 0,
sizeof(loaderInitializeInfoAndroid));
431 loaderInitializeInfoAndroid.type = XR_TYPE_LOADER_INIT_INFO_ANDROID_KHR;
432 loaderInitializeInfoAndroid.next = NULL;
433 loaderInitializeInfoAndroid.applicationVM = m_javaVM;
434 loaderInitializeInfoAndroid.applicationContext = m_androidActivity.object();
435 XrResult xrResult = xrInitializeLoaderKHR((XrLoaderInitInfoBaseHeaderKHR*)&loaderInitializeInfoAndroid);
436 if (xrResult != XR_SUCCESS) {
437 qWarning(
"Failed to initialize OpenXR Loader: %s", to_string(xrResult));
444 auto graphicsAPI = QQuickWindow::graphicsApi();
446 m_graphics =
nullptr;
447#ifdef XR_USE_GRAPHICS_API_VULKAN
448 if (graphicsAPI == QSGRendererInterface::Vulkan)
449 m_graphics =
new QOpenXRGraphicsVulkan;
451#ifdef XR_USE_GRAPHICS_API_D3D11
452 if (graphicsAPI == QSGRendererInterface::Direct3D11)
453 m_graphics =
new QOpenXRGraphicsD3D11;
455#ifdef XR_USE_GRAPHICS_API_D3D12
456 if (graphicsAPI == QSGRendererInterface::Direct3D12)
457 m_graphics =
new QOpenXRGraphicsD3D12;
459#ifdef XR_USE_GRAPHICS_API_OPENGL
460 if (graphicsAPI == QSGRendererInterface::OpenGL)
461 m_graphics =
new QOpenXRGraphicsOpenGL;
463#ifdef XR_USE_GRAPHICS_API_OPENGL_ES
464 if (graphicsAPI == QSGRendererInterface::OpenGL)
465 m_graphics =
new QOpenXRGraphicsOpenGLES;
467#ifdef XR_USE_GRAPHICS_API_METAL
468 if (graphicsAPI == QSGRendererInterface::Metal)
469 m_graphics =
new QOpenXRGraphicsMetal;
473 qWarning() <<
"The Qt Quick Scenegraph is not using a supported RHI mode:" << graphicsAPI;
478 checkXrExtensions(
nullptr);
481 m_spaceExtension = QQuick3DXrAnchorManager::instance();
484 XrResult result = createXrInstance();
485 if (result != XR_SUCCESS) {
486 setErrorString(result,
"xrCreateInstance");
488 m_graphics =
nullptr;
495 setupDebugMessenger();
498 result = initializeSystem();
499 if (result != XR_SUCCESS) {
500 setErrorString(result,
"xrGetSystem");
502 m_graphics =
nullptr;
507 if (!q->setupGraphics()) {
508 m_errorString = QObject::tr(
"Failed to set up 3D API integration");
510 m_graphics =
nullptr;
515 XrSessionCreateInfo xrSessionInfo{};
516 xrSessionInfo.type = XR_TYPE_SESSION_CREATE_INFO;
517 xrSessionInfo.next = m_graphics->handle();
518 xrSessionInfo.systemId = m_systemId;
520 result = xrCreateSession(m_instance, &xrSessionInfo, &m_session);
521 if (result != XR_SUCCESS) {
522 setErrorString(result,
"xrCreateSession");
524 m_graphics =
nullptr;
529 if (m_colorspaceExtensionSupported)
530 setupMetaQuestColorSpaces();
531 if (m_displayRefreshRateExtensionSupported)
532 setupMetaQuestRefreshRates();
533 if (m_spaceExtensionSupported)
534 m_spaceExtension->initialize(m_instance, m_session);
536 checkReferenceSpaces();
539 m_inputManager = QQuick3DXrInputManager::instance();
540 if (QSSG_GUARD(m_inputManager !=
nullptr))
541 QQuick3DXrInputManagerPrivate::get(m_inputManager)->init(m_instance, m_session);
543 if (!setupAppSpace())
545 if (!setupViewSpace())
548 if (!createSwapchains())
556 if (m_inputManager) {
557 QQuick3DXrInputManagerPrivate::get(m_inputManager)->teardown();
558 m_inputManager =
nullptr;
561 if (m_spaceExtension) {
563 m_spaceExtension =
nullptr;
566 if (m_passthroughLayer)
567 destroyMetaQuestPassthroughLayer();
568 if (m_passthroughFeature)
569 destroyMetaQuestPassthrough();
573 if (m_appSpace != XR_NULL_HANDLE) {
574 xrDestroySpace(m_appSpace);
577 if (m_viewSpace != XR_NULL_HANDLE)
578 xrDestroySpace(m_viewSpace);
580 xrDestroySession(m_session);
582#ifdef XR_EXT_debug_utils
583 if (m_debugMessenger) {
584 m_xrDestroyDebugUtilsMessengerEXT(m_debugMessenger);
585 m_debugMessenger = XR_NULL_HANDLE;
589 xrDestroyInstance(m_instance);
594 m_graphics->releaseResources();
599 Q_ASSERT(m_session != XR_NULL_HANDLE);
602 if (!checkXrResult(xrEnumerateReferenceSpaces(m_session, 0, &spaceCount,
nullptr))) {
603 qWarning(
"Failed to enumerate reference spaces");
606 m_availableReferenceSpace.resize(spaceCount);
607 if (!checkXrResult(xrEnumerateReferenceSpaces(m_session, spaceCount, &spaceCount, m_availableReferenceSpace.data()))) {
608 qWarning(
"Failed to enumerate reference spaces");
612 qCDebug(lcQuick3DXr,
"Available reference spaces: %d", spaceCount);
613 for (XrReferenceSpaceType space : m_availableReferenceSpace) {
614 qCDebug(lcQuick3DXr,
" Name: %s", to_string(space));
620 return m_availableReferenceSpace.contains(type);
625 Q_Q(QQuick3DXrManager);
627 Q_ASSERT(m_session != XR_NULL_HANDLE);
629 XrPosef identityPose;
630 identityPose.orientation.w = 1;
631 identityPose.orientation.x = 0;
632 identityPose.orientation.y = 0;
633 identityPose.orientation.z = 0;
634 identityPose.position.x = 0;
635 identityPose.position.y = 0;
636 identityPose.position.z = 0;
638 XrReferenceSpaceType newReferenceSpace;
639 XrSpace newAppSpace = XR_NULL_HANDLE;
640 m_isEmulatingLocalFloor =
false;
642 if (isReferenceSpaceAvailable(m_requestedReferenceSpace)) {
643 newReferenceSpace = m_requestedReferenceSpace;
644 }
else if (m_requestedReferenceSpace == XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT &&
645 isReferenceSpaceAvailable(XR_REFERENCE_SPACE_TYPE_STAGE)) {
646 m_isEmulatingLocalFloor =
true;
647 m_isFloorResetPending =
true;
648 newReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
650 qWarning(
"Requested reference space is not available");
651 newReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
655 qCDebug(lcQuick3DXr,
"Creating new reference space for app space: %s", to_string(newReferenceSpace));
656 XrReferenceSpaceCreateInfo referenceSpaceCreateInfo{};
657 referenceSpaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
658 referenceSpaceCreateInfo.poseInReferenceSpace = identityPose;
659 referenceSpaceCreateInfo.referenceSpaceType = newReferenceSpace;
660 if (!checkXrResult(xrCreateReferenceSpace(m_session, &referenceSpaceCreateInfo, &newAppSpace))) {
661 qWarning(
"Failed to create app space");
666 xrDestroySpace(m_appSpace);
668 m_appSpace = newAppSpace;
669 m_referenceSpace = newReferenceSpace;
672 if (!m_isFloorResetPending)
673 emit q->referenceSpaceChanged();
681 Q_Q(QQuick3DXrManager);
685 if (m_requestedReferenceSpace != m_referenceSpace && !m_isFloorResetPending) {
686 if (!setupAppSpace()) {
688 qWarning(
"Setting requested reference space failed");
689 m_requestedReferenceSpace = m_referenceSpace;
698 if (m_isFloorResetPending) {
699 if (!resetEmulatedFloorHeight(predictedDisplayTime)) {
701 m_requestedReferenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL;
702 emit q->referenceSpaceChanged();
711 Q_ASSERT(m_session != XR_NULL_HANDLE);
713 XrPosef identityPose;
714 identityPose.orientation.w = 1;
715 identityPose.orientation.x = 0;
716 identityPose.orientation.y = 0;
717 identityPose.orientation.z = 0;
718 identityPose.position.x = 0;
719 identityPose.position.y = 0;
720 identityPose.position.z = 0;
722 XrSpace newViewSpace = XR_NULL_HANDLE;
724 XrReferenceSpaceCreateInfo referenceSpaceCreateInfo{};
725 referenceSpaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
726 referenceSpaceCreateInfo.poseInReferenceSpace = identityPose;
727 referenceSpaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_VIEW;
728 if (!checkXrResult(xrCreateReferenceSpace(m_session, &referenceSpaceCreateInfo, &newViewSpace))) {
729 qWarning(
"Failed to create view space");
733 if (m_viewSpace != XR_NULL_HANDLE)
734 xrDestroySpace(m_viewSpace);
736 m_viewSpace = newViewSpace;
743 Q_Q(QQuick3DXrManager);
745 Q_ASSERT(m_isEmulatingLocalFloor);
747 m_isFloorResetPending =
false;
749 XrPosef identityPose;
750 identityPose.orientation.w = 1;
751 identityPose.orientation.x = 0;
752 identityPose.orientation.y = 0;
753 identityPose.orientation.z = 0;
754 identityPose.position.x = 0;
755 identityPose.position.y = 0;
756 identityPose.position.z = 0;
758 XrSpace localSpace = XR_NULL_HANDLE;
759 XrSpace stageSpace = XR_NULL_HANDLE;
761 XrReferenceSpaceCreateInfo createInfo{};
762 createInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
763 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
764 createInfo.poseInReferenceSpace = identityPose;
766 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &localSpace))) {
767 qWarning(
"Failed to create local space (for emulated LOCAL_FLOOR space)");
771 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
772 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &stageSpace))) {
773 qWarning(
"Failed to create stage space (for emulated LOCAL_FLOOR space)");
774 xrDestroySpace(localSpace);
778 XrSpaceLocation stageLocation{};
779 stageLocation.type = XR_TYPE_SPACE_LOCATION;
780 stageLocation.pose = identityPose;
782 if (!checkXrResult(xrLocateSpace(stageSpace, localSpace, predictedDisplayTime, &stageLocation))) {
783 qWarning(
"Failed to locate STAGE space in LOCAL space, in order to emulate LOCAL_FLOOR");
784 xrDestroySpace(localSpace);
785 xrDestroySpace(stageSpace);
789 xrDestroySpace(localSpace);
790 xrDestroySpace(stageSpace);
792 XrSpace newAppSpace = XR_NULL_HANDLE;
793 createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
794 createInfo.poseInReferenceSpace.position.y = stageLocation.pose.position.y;
795 if (!checkXrResult(xrCreateReferenceSpace(m_session, &createInfo, &newAppSpace))) {
796 qWarning(
"Failed to recreate emulated LOCAL_FLOOR play space with latest floor estimate");
800 xrDestroySpace(m_appSpace);
801 m_appSpace = newAppSpace;
802 m_referenceSpace = XR_REFERENCE_SPACE_TYPE_LOCAL_FLOOR_EXT;
803 emit q->referenceSpaceChanged();
810 Q_ASSERT(m_session != XR_NULL_HANDLE);
811 Q_ASSERT(m_configViews.isEmpty());
812 Q_ASSERT(m_swapchains.isEmpty());
814 XrSystemProperties systemProperties{};
815 systemProperties.type = XR_TYPE_SYSTEM_PROPERTIES;
817 XrSystemHandTrackingPropertiesEXT handTrackingSystemProperties{};
818 handTrackingSystemProperties.type = XR_TYPE_SYSTEM_HAND_TRACKING_PROPERTIES_EXT;
819 systemProperties.next = &handTrackingSystemProperties;
821 if (!checkXrResult(xrGetSystemProperties(m_instance, m_systemId, &systemProperties))) {
822 qWarning(
"Failed to get OpenXR system properties");
825 qCDebug(lcQuick3DXr,
"System Properties: Name=%s VendorId=%d", systemProperties.systemName, systemProperties.vendorId);
826 qCDebug(lcQuick3DXr,
"System Graphics Properties: MaxWidth=%d MaxHeight=%d MaxLayers=%d",
827 systemProperties.graphicsProperties.maxSwapchainImageWidth,
828 systemProperties.graphicsProperties.maxSwapchainImageHeight,
829 systemProperties.graphicsProperties.maxLayerCount);
830 qCDebug(lcQuick3DXr,
"System Tracking Properties: OrientationTracking=%s PositionTracking=%s",
831 systemProperties.trackingProperties.orientationTracking == XR_TRUE ?
"True" :
"False",
832 systemProperties.trackingProperties.positionTracking == XR_TRUE ?
"True" :
"False");
833 qCDebug(lcQuick3DXr,
"System Hand Tracking Properties: handTracking=%s",
834 handTrackingSystemProperties.supportsHandTracking == XR_TRUE ?
"True" :
"False");
838 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
845 qWarning(
"Failed to enumerate view configurations");
848 m_configViews.resize(viewCount, {XR_TYPE_VIEW_CONFIGURATION_VIEW,
nullptr, 0, 0, 0, 0, 0, 0});
849 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
854 m_configViews.data())))
856 qWarning(
"Failed to enumerate view configurations");
859 m_views.resize(viewCount, {XR_TYPE_VIEW,
nullptr, {}, {}});
860 m_projectionLayerViews.resize(viewCount, {});
861 m_layerDepthInfos.resize(viewCount, {});
866 uint32_t swapchainFormatCount;
867 if (!checkXrResult(xrEnumerateSwapchainFormats(m_session, 0, &swapchainFormatCount,
nullptr))) {
868 qWarning(
"Failed to enumerate swapchain formats");
871 QVector<int64_t> swapchainFormats(swapchainFormatCount);
872 if (!checkXrResult(xrEnumerateSwapchainFormats(m_session,
873 swapchainFormats.size(),
874 &swapchainFormatCount,
875 swapchainFormats.data())))
877 qWarning(
"Failed to enumerate swapchain formats");
881 Q_ASSERT(
static_cast<qsizetype>(swapchainFormatCount) == swapchainFormats.size());
882 m_colorSwapchainFormat = m_graphics->colorSwapchainFormat(swapchainFormats);
883 if (m_compositionLayerDepthSupported)
884 m_depthSwapchainFormat = m_graphics->depthSwapchainFormat(swapchainFormats);
888 QString swapchainFormatsString;
889 for (int64_t format : swapchainFormats) {
890 const bool selectedColor = format == m_colorSwapchainFormat;
891 const bool selectedDepth = format == m_depthSwapchainFormat;
892 swapchainFormatsString += u" ";
894 swapchainFormatsString += u"[";
895 else if (selectedDepth)
896 swapchainFormatsString += u"<";
897 swapchainFormatsString += QString::number(format);
899 swapchainFormatsString += u"]";
900 else if (selectedDepth)
901 swapchainFormatsString += u">";
903 qCDebug(lcQuick3DXr,
"Swapchain formats: %s", qPrintable(swapchainFormatsString));
906 const XrViewConfigurationView &vp = m_configViews[0];
917 if (m_multiviewRendering) {
919 XrSwapchainCreateInfo swapchainCreateInfo{};
920 swapchainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
921 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT | XR_SWAPCHAIN_USAGE_MUTABLE_FORMAT_BIT;
922 swapchainCreateInfo.format = m_colorSwapchainFormat;
923 swapchainCreateInfo.sampleCount = 1;
924 swapchainCreateInfo.width = vp.recommendedImageRectWidth;
925 swapchainCreateInfo.height = vp.recommendedImageRectHeight;
926 swapchainCreateInfo.faceCount = 1;
927 swapchainCreateInfo.arraySize = viewCount;
928 swapchainCreateInfo.mipCount = 1;
930 qCDebug(lcQuick3DXr,
"Creating multiview swapchain for %u view(s) with dimensions Width=%d Height=%d SampleCount=%d Format=%llx",
932 vp.recommendedImageRectWidth,
933 vp.recommendedImageRectHeight,
935 static_cast<
long long unsigned int>(m_colorSwapchainFormat));
938 swapchain.width = swapchainCreateInfo.width;
939 swapchain.height = swapchainCreateInfo.height;
940 swapchain.arraySize = swapchainCreateInfo.arraySize;
941 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
942 uint32_t imageCount = 0;
943 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
944 qWarning(
"Failed to enumerate swapchain images");
948 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
949 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
950 qWarning(
"Failed to enumerate swapchain images");
954 m_swapchains.append(swapchain);
955 m_swapchainImages.insert(swapchain.handle, swapchainImages);
957 qWarning(
"xrCreateSwapchain failed (multiview)");
965 if (m_compositionLayerDepthSupported && m_depthSwapchainFormat > 0) {
966 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
967 swapchainCreateInfo.format = m_depthSwapchainFormat;
968 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
969 uint32_t imageCount = 0;
970 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
971 qWarning(
"Failed to enumerate depth swapchain images");
975 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
976 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
977 qWarning(
"Failed to enumerate depth swapchain images");
981 m_depthSwapchains.append(swapchain);
982 m_depthSwapchainImages.insert(swapchain.handle, swapchainImages);
984 qWarning(
"xrCreateSwapchain failed for depth swapchain (multiview)");
990 for (uint32_t i = 0; i < viewCount; i++) {
991 qCDebug(lcQuick3DXr,
"Creating swapchain for view %u with dimensions Width=%d Height=%d SampleCount=%d Format=%llx",
993 vp.recommendedImageRectWidth,
994 vp.recommendedImageRectHeight,
996 static_cast<
long long unsigned int>(m_colorSwapchainFormat));
999 XrSwapchainCreateInfo swapchainCreateInfo{};
1000 swapchainCreateInfo.type = XR_TYPE_SWAPCHAIN_CREATE_INFO;
1001 swapchainCreateInfo.arraySize = 1;
1002 swapchainCreateInfo.format = m_colorSwapchainFormat;
1003 swapchainCreateInfo.width = vp.recommendedImageRectWidth;
1004 swapchainCreateInfo.height = vp.recommendedImageRectHeight;
1005 swapchainCreateInfo.mipCount = 1;
1006 swapchainCreateInfo.faceCount = 1;
1007 swapchainCreateInfo.sampleCount = 1;
1008 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_SAMPLED_BIT | XR_SWAPCHAIN_USAGE_COLOR_ATTACHMENT_BIT;
1009 Swapchain swapchain;
1010 swapchain.width = swapchainCreateInfo.width;
1011 swapchain.height = swapchainCreateInfo.height;
1012 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1013 uint32_t imageCount = 0;
1014 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1015 qWarning(
"Failed to enumerate swapchain images");
1019 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1020 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1021 qWarning(
"Failed to enumerate swapchain images");
1025 m_swapchains.append(swapchain);
1026 m_swapchainImages.insert(swapchain.handle, swapchainImages);
1028 qWarning(
"xrCreateSwapchain failed (view %u)", viewCount);
1032 if (m_compositionLayerDepthSupported && m_depthSwapchainFormat > 0) {
1033 swapchainCreateInfo.usageFlags = XR_SWAPCHAIN_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
1034 swapchainCreateInfo.format = m_depthSwapchainFormat;
1035 if (checkXrResult(xrCreateSwapchain(m_session, &swapchainCreateInfo, &swapchain.handle))) {
1036 uint32_t imageCount = 0;
1037 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, 0, &imageCount,
nullptr))) {
1038 qWarning(
"Failed to enumerate depth swapchain images");
1042 auto swapchainImages = m_graphics->allocateSwapchainImages(imageCount, swapchain.handle);
1043 if (!checkXrResult(xrEnumerateSwapchainImages(swapchain.handle, imageCount, &imageCount, swapchainImages[0]))) {
1044 qWarning(
"Failed to enumerate depth swapchain images");
1048 m_depthSwapchains.append(swapchain);
1049 m_depthSwapchainImages.insert(swapchain.handle, swapchainImages);
1051 qWarning(
"xrCreateSwapchain failed for depth swapchain (view %u)", viewCount);
1058 if (m_multiviewRendering) {
1059 if (m_swapchains.isEmpty())
1061 if (m_compositionLayerDepthSupported && m_depthSwapchains.isEmpty())
1064 if (m_swapchains.count() != qsizetype(viewCount))
1066 if (m_compositionLayerDepthSupported && m_depthSwapchains.count() != qsizetype(viewCount))
1071 for (uint32_t i = 0; i < viewCount; ++i) {
1072 m_projectionLayerViews[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
1073 m_projectionLayerViews[i].next =
nullptr;
1074 m_projectionLayerViews[i].subImage.swapchain = m_swapchains[0].handle;
1075 m_projectionLayerViews[i].subImage.imageArrayIndex = i;
1076 m_projectionLayerViews[i].subImage.imageRect.offset.x = 0;
1077 m_projectionLayerViews[i].subImage.imageRect.offset.y = 0;
1078 m_projectionLayerViews[i].subImage.imageRect.extent.width = vp.recommendedImageRectWidth;
1079 m_projectionLayerViews[i].subImage.imageRect.extent.height = vp.recommendedImageRectHeight;
1081 if (m_compositionLayerDepthSupported) {
1082 m_layerDepthInfos[i].type = XR_TYPE_COMPOSITION_LAYER_DEPTH_INFO_KHR;
1083 m_layerDepthInfos[i].next =
nullptr;
1084 m_layerDepthInfos[i].subImage.swapchain = m_depthSwapchains[0].handle;
1085 m_layerDepthInfos[i].subImage.imageArrayIndex = i;
1086 m_layerDepthInfos[i].subImage.imageRect.offset.x = 0;
1087 m_layerDepthInfos[i].subImage.imageRect.offset.y = 0;
1088 m_layerDepthInfos[i].subImage.imageRect.extent.width = vp.recommendedImageRectWidth;
1089 m_layerDepthInfos[i].subImage.imageRect.extent.height = vp.recommendedImageRectHeight;
1094 if (m_foveationExtensionSupported)
1095 setupMetaQuestFoveation();
1102 if (m_samples == samples)
1105 m_samples = samples;
1113 return m_enabledExtensions;
1118 return m_runtimeName;
1123 return m_runtimeVersion;
1128 Q_Q(QQuick3DXrManager);
1129 QRhi *rhi = q->m_renderControl->rhi();
1130 if (m_multiviewRendering == enable || !rhi)
1132 if (enable && !rhi->isFeatureSupported(QRhi::MultiView)) {
1133 qWarning(
"Quick 3D XR: Multiview rendering was enabled, but is reported as unsupported from the current QRhi backend (%s)",
1134 rhi->backendName());
1137 m_multiviewRendering = enable;
1138 qCDebug(lcQuick3DXr,
"Multiview rendering %s", m_multiviewRendering ?
"enabled" :
"disabled");
1139 if (!m_swapchains.isEmpty()) {
1140 qCDebug(lcQuick3DXr,
"OpenXR swapchain already exists, creating new one due to change in multiview mode");
1144 emit q->multiViewRenderingEnabledChanged();
1152 if (m_passthroughSupported) {
1153 m_enablePassthrough = enable;
1154 if (m_enablePassthrough) {
1155 if (m_passthroughFeature == XR_NULL_HANDLE)
1156 createMetaQuestPassthrough();
1158 startMetaQuestPassthrough();
1160 if (m_passthroughLayer == XR_NULL_HANDLE)
1161 createMetaQuestPassthroughLayer();
1163 resumeMetaQuestPassthroughLayer();
1166 if (m_passthroughLayer)
1167 pauseMetaQuestPassthroughLayer();
1169 if (m_passthroughFeature)
1170 pauseMetaQuestPassthrough();
1173 return m_passthroughSupported;
1178 if (m_submitLayerDepth == enable)
1181 if (m_compositionLayerDepthSupported) {
1183 qCDebug(lcQuick3DXr,
"Enabling submitLayerDepth");
1185 m_submitLayerDepth = enable;
1191 XrReferenceSpaceType referenceSpace = getXrReferenceSpaceType(newReferenceSpace);
1192 if (m_referenceSpace == referenceSpace)
1195 m_requestedReferenceSpace = referenceSpace;
1203 return getReferenceSpaceType(m_referenceSpace);
1214 *exitRenderLoop =
false;
1215 *requestRestart =
false;
1217 auto readNextEvent = [
this]() {
1220 XrEventDataBaseHeader* baseHeader =
reinterpret_cast<XrEventDataBaseHeader*>(&m_eventDataBuffer);
1221 *baseHeader = {XR_TYPE_EVENT_DATA_BUFFER,
nullptr};
1222 const XrResult xr = xrPollEvent(m_instance, &m_eventDataBuffer);
1223 if (xr == XR_SUCCESS) {
1224 if (baseHeader->type == XR_TYPE_EVENT_DATA_EVENTS_LOST) {
1225 const XrEventDataEventsLost*
const eventsLost =
reinterpret_cast<
const XrEventDataEventsLost*>(baseHeader);
1226 qCDebug(lcQuick3DXr,
"%d events lost", eventsLost->lostEventCount);
1232 return static_cast<XrEventDataBaseHeader*>(
nullptr);
1235 auto handleSessionStateChangedEvent = [
this](
const XrEventDataSessionStateChanged& stateChangedEvent,
1236 bool* exitRenderLoop,
1237 bool* requestRestart) {
1238 const XrSessionState oldState = m_sessionState;
1239 m_sessionState = stateChangedEvent.state;
1241 qCDebug(lcQuick3DXr,
"XrEventDataSessionStateChanged: state %s->%s time=%lld",
1242 to_string(oldState),
1243 to_string(m_sessionState),
1244 static_cast<
long long int>(stateChangedEvent.time));
1246 if ((stateChangedEvent.session != XR_NULL_HANDLE) && (stateChangedEvent.session != m_session)) {
1247 qCDebug(lcQuick3DXr,
"XrEventDataSessionStateChanged for unknown session");
1251 switch (m_sessionState) {
1252 case XR_SESSION_STATE_READY: {
1253 Q_ASSERT(m_session != XR_NULL_HANDLE);
1254 XrSessionBeginInfo sessionBeginInfo{};
1255 sessionBeginInfo.type = XR_TYPE_SESSION_BEGIN_INFO;
1256 sessionBeginInfo.primaryViewConfigurationType = m_viewConfigType;
1257 if (!checkXrResult(xrBeginSession(m_session, &sessionBeginInfo))) {
1258 qWarning(
"xrBeginSession failed");
1261 m_sessionRunning =
true;
1264 case XR_SESSION_STATE_STOPPING: {
1265 Q_ASSERT(m_session != XR_NULL_HANDLE);
1266 m_sessionRunning =
false;
1267 if (!checkXrResult(xrEndSession(m_session)))
1268 qWarning(
"xrEndSession failed");
1271 case XR_SESSION_STATE_EXITING: {
1272 *exitRenderLoop =
true;
1274 *requestRestart =
false;
1277 case XR_SESSION_STATE_LOSS_PENDING: {
1278 *exitRenderLoop =
true;
1280 *requestRestart =
true;
1289 while (
const XrEventDataBaseHeader* event = readNextEvent()) {
1290 switch (event->type) {
1291 case XR_TYPE_EVENT_DATA_INSTANCE_LOSS_PENDING: {
1292 const auto& instanceLossPending = *
reinterpret_cast<
const XrEventDataInstanceLossPending*>(event);
1293 qCDebug(lcQuick3DXr,
"XrEventDataInstanceLossPending by %lld",
static_cast<
long long int>(instanceLossPending.lossTime));
1294 *exitRenderLoop =
true;
1295 *requestRestart =
true;
1298 case XR_TYPE_EVENT_DATA_SESSION_STATE_CHANGED: {
1299 auto sessionStateChangedEvent = *
reinterpret_cast<
const XrEventDataSessionStateChanged*>(event);
1300 handleSessionStateChangedEvent(sessionStateChangedEvent, exitRenderLoop, requestRestart);
1303 case XR_TYPE_EVENT_DATA_INTERACTION_PROFILE_CHANGED:
1305 case XR_TYPE_EVENT_DATA_SPACE_SET_STATUS_COMPLETE_FB:
1306 case XR_TYPE_EVENT_DATA_SPACE_QUERY_RESULTS_AVAILABLE_FB:
1307 case XR_TYPE_EVENT_DATA_SPACE_QUERY_COMPLETE_FB:
1308 case XR_TYPE_EVENT_DATA_SCENE_CAPTURE_COMPLETE_FB:
1310 if (m_spaceExtension)
1311 m_spaceExtension->handleEvent(event);
1313 case XR_TYPE_EVENT_DATA_REFERENCE_SPACE_CHANGE_PENDING:
1315 qCDebug(lcQuick3DXr,
"Ignoring event type %d", event->type);
1323 XrDuration predictedDisplayPeriod,
1324 XrCompositionLayerProjection &layer)
1326 Q_Q(QQuick3DXrManager);
1327 auto *xrOrigin = q->m_xrOrigin;
1328 auto *animationDriver = q->m_animationDriver;
1329 auto *renderControl = q->m_renderControl;
1333 XrViewState viewState{};
1334 viewState.type = XR_TYPE_VIEW_STATE;
1335 quint32 viewCapacityInput = m_views.size();
1336 quint32 viewCountOutput;
1339 updateAppSpace(predictedDisplayTime);
1341 XrViewLocateInfo viewLocateInfo{};
1342 viewLocateInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
1343 viewLocateInfo.viewConfigurationType = m_viewConfigType;
1344 viewLocateInfo.displayTime = predictedDisplayTime;
1345 viewLocateInfo.space = m_appSpace;
1347 res = xrLocateViews(m_session, &viewLocateInfo, &viewState, viewCapacityInput, &viewCountOutput, m_views.data());
1348 if (XR_UNQUALIFIED_SUCCESS(res)) {
1349 Q_ASSERT(viewCountOutput == viewCapacityInput);
1350 Q_ASSERT(
static_cast<qsizetype>(viewCountOutput) == m_configViews.size());
1351 Q_ASSERT(
static_cast<qsizetype>(viewCountOutput) == m_projectionLayerViews.size());
1352 Q_ASSERT(m_multiviewRendering ? viewCountOutput == m_swapchains[0].arraySize :
static_cast<qsizetype>(viewCountOutput) == m_swapchains.size());
1355 XrSpaceLocation location{};
1356 location.type = XR_TYPE_SPACE_LOCATION;
1357 if (checkXrResult(xrLocateSpace(m_viewSpace, m_appSpace, predictedDisplayTime, &location))) {
1358 QVector3D position = QVector3D(location.pose.position.x,
1359 location.pose.position.y,
1360 location.pose.position.z) * 100.0f;
1361 QQuaternion rotation(location.pose.orientation.w,
1362 location.pose.orientation.x,
1363 location.pose.orientation.y,
1364 location.pose.orientation.z);
1366 xrOrigin->updateTrackedCamera(position, rotation);
1370 if (QSSG_GUARD(m_inputManager !=
nullptr))
1371 QQuick3DXrInputManagerPrivate::get(m_inputManager)->updatePoses(predictedDisplayTime, m_appSpace);
1374 if (m_spaceExtension)
1375 m_spaceExtension->updateAnchors(predictedDisplayTime, m_appSpace);
1377 if (m_handtrackingExtensionSupported && m_inputManager)
1378 QQuick3DXrInputManagerPrivate::get(m_inputManager)->updateHandtracking(predictedDisplayTime, m_appSpace, m_handtrackingAimExtensionSupported);
1383 const qint64 displayPeriodMS = predictedDisplayPeriod / 1000000;
1384 const qint64 displayDeltaMS = (predictedDisplayTime - m_previousTime) / 1000000;
1386 if (m_previousTime == 0 || !animationDriver->isRunning()) {
1387 animationDriver->setStep(displayPeriodMS);
1389 if (displayDeltaMS > displayPeriodMS)
1390 animationDriver->setStep(displayPeriodMS);
1392 animationDriver->setStep(displayDeltaMS);
1393 animationDriver->advance();
1395 m_previousTime = predictedDisplayTime;
1397#if QT_CONFIG(graphicsframecapture)
1399 m_frameCapture->startCaptureFrame();
1402 if (m_submitLayerDepth && m_samples > 1) {
1403 if (!renderControl->rhi()->isFeatureSupported(QRhi::ResolveDepthStencil)) {
1404 static bool warned =
false;
1407 qWarning(
"Quick3D XR: Submitting depth buffer with MSAA cannot be enabled"
1408 " when depth-stencil resolve is not supported by the underlying 3D API (%s)",
1409 renderControl->rhi()->backendName());
1411 m_submitLayerDepth =
false;
1415 if (m_multiviewRendering) {
1416 const Swapchain swapchain = m_swapchains[0];
1419 XrSwapchainImageAcquireInfo acquireInfo{};
1420 acquireInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
1421 uint32_t swapchainImageIndex = 0;
1422 if (!checkXrResult(xrAcquireSwapchainImage(swapchain.handle, &acquireInfo, &swapchainImageIndex))) {
1423 qWarning(
"Failed to acquire swapchain image (multiview)");
1426 XrSwapchainImageWaitInfo waitInfo{};
1427 waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
1428 waitInfo.timeout = XR_INFINITE_DURATION;
1429 if (!checkXrResult(xrWaitSwapchainImage(swapchain.handle, &waitInfo))) {
1430 qWarning(
"Failed to wait for swapchain image (multiview)");
1433 XrSwapchainImageBaseHeader *swapchainImage = m_swapchainImages[swapchain.handle][swapchainImageIndex];
1435 XrSwapchainImageBaseHeader *depthSwapchainImage =
nullptr;
1436 if (m_submitLayerDepth && !m_depthSwapchains.isEmpty()) {
1437 if (checkXrResult(xrAcquireSwapchainImage(m_depthSwapchains[0].handle, &acquireInfo, &swapchainImageIndex))) {
1438 if (checkXrResult(xrWaitSwapchainImage(m_depthSwapchains[0].handle, &waitInfo)))
1439 depthSwapchainImage = m_depthSwapchainImages[m_depthSwapchains[0].handle][swapchainImageIndex];
1441 qWarning(
"Failed to wait for depth swapchain image (multiview)");
1443 qWarning(
"Failed to acquire depth swapchain image (multiview)");
1450 for (uint32_t i = 0; i < viewCountOutput; i++) {
1452 m_projectionLayerViews[i].pose = m_views[i].pose;
1453 m_projectionLayerViews[i].fov = m_views[i].fov;
1455 updateCameraMultiview(0, viewCountOutput);
1461 doRender(m_projectionLayerViews[0].subImage,
1463 depthSwapchainImage);
1465 for (uint32_t i = 0; i < viewCountOutput; i++) {
1466 if (m_submitLayerDepth) {
1467 m_layerDepthInfos[i].minDepth = 0;
1468 m_layerDepthInfos[i].maxDepth = 1;
1469 QQuick3DXrEyeCamera *cam = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
1470 m_layerDepthInfos[i].nearZ = cam ? cam->clipNear() : 1.0f;
1471 m_layerDepthInfos[i].farZ = cam ? cam->clipFar() : 10000.0f;
1472 m_projectionLayerViews[i].next = &m_layerDepthInfos[i];
1474 m_projectionLayerViews[i].next =
nullptr;
1479 XrSwapchainImageReleaseInfo releaseInfo{};
1480 releaseInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
1481 if (!checkXrResult(xrReleaseSwapchainImage(swapchain.handle, &releaseInfo)))
1482 qWarning(
"Failed to release swapchain image");
1483 if (depthSwapchainImage) {
1484 if (!checkXrResult(xrReleaseSwapchainImage(m_depthSwapchains[0].handle, &releaseInfo)))
1485 qWarning(
"Failed to release depth swapchain image");
1488 for (uint32_t i = 0; i < viewCountOutput; i++) {
1490 const Swapchain viewSwapchain = m_swapchains[i];
1493 XrSwapchainImageAcquireInfo acquireInfo{};
1494 acquireInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_ACQUIRE_INFO;
1495 uint32_t swapchainImageIndex = 0;
1496 if (!checkXrResult(xrAcquireSwapchainImage(viewSwapchain.handle, &acquireInfo, &swapchainImageIndex))) {
1497 qWarning(
"Failed to acquire swapchain image");
1500 XrSwapchainImageWaitInfo waitInfo{};
1501 waitInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_WAIT_INFO;
1502 waitInfo.timeout = XR_INFINITE_DURATION;
1503 if (!checkXrResult(xrWaitSwapchainImage(viewSwapchain.handle, &waitInfo))) {
1504 qWarning(
"Failed to wait for swapchain image");
1507 XrSwapchainImageBaseHeader *swapchainImage = m_swapchainImages[viewSwapchain.handle][swapchainImageIndex];
1509 XrSwapchainImageBaseHeader *depthSwapchainImage =
nullptr;
1510 if (m_submitLayerDepth && !m_depthSwapchains.isEmpty()) {
1511 if (checkXrResult(xrAcquireSwapchainImage(m_depthSwapchains[i].handle, &acquireInfo, &swapchainImageIndex))) {
1512 if (checkXrResult(xrWaitSwapchainImage(m_depthSwapchains[i].handle, &waitInfo)))
1513 depthSwapchainImage = m_depthSwapchainImages[m_depthSwapchains[i].handle][swapchainImageIndex];
1515 qWarning(
"Failed to wait for depth swapchain image");
1517 qWarning(
"Failed to acquire depth swapchain image");
1521 m_projectionLayerViews[i].subImage.swapchain = viewSwapchain.handle;
1522 m_projectionLayerViews[i].subImage.imageArrayIndex = 0;
1523 m_projectionLayerViews[i].pose = m_views[i].pose;
1524 m_projectionLayerViews[i].fov = m_views[i].fov;
1526 updateCameraNonMultiview(i, m_projectionLayerViews[i]);
1528 doRender(m_projectionLayerViews[i].subImage,
1530 depthSwapchainImage);
1532 if (depthSwapchainImage) {
1533 m_layerDepthInfos[i].subImage.swapchain = m_depthSwapchains[i].handle;
1534 m_layerDepthInfos[i].subImage.imageArrayIndex = 0;
1535 m_layerDepthInfos[i].minDepth = 0;
1536 m_layerDepthInfos[i].maxDepth = 1;
1537 QQuick3DXrEyeCamera *cam = xrOrigin ? xrOrigin->eyeCamera(i) :
nullptr;
1538 m_layerDepthInfos[i].nearZ = cam ? cam->clipNear() : 1.0f;
1539 m_layerDepthInfos[i].farZ = cam ? cam->clipFar() : 10000.0f;
1540 m_projectionLayerViews[i].next = &m_layerDepthInfos[i];
1542 m_projectionLayerViews[i].next =
nullptr;
1545 XrSwapchainImageReleaseInfo releaseInfo{};
1546 releaseInfo.type = XR_TYPE_SWAPCHAIN_IMAGE_RELEASE_INFO;
1547 if (!checkXrResult(xrReleaseSwapchainImage(viewSwapchain.handle, &releaseInfo)))
1548 qWarning(
"Failed to release swapchain image");
1549 if (depthSwapchainImage) {
1550 if (!checkXrResult(xrReleaseSwapchainImage(m_depthSwapchains[i].handle, &releaseInfo)))
1551 qWarning(
"Failed to release depth swapchain image");
1556#if QT_CONFIG(graphicsframecapture)
1558 m_frameCapture->endCaptureFrame();
1561 layer.space = m_appSpace;
1562 layer.viewCount = (uint32_t)m_projectionLayerViews.size();
1563 layer.views = m_projectionLayerViews.data();
1567 qCDebug(lcQuick3DXr,
"xrLocateViews returned qualified success code: %s", to_string(res));
1572 const XrSwapchainImageBaseHeader *swapchainImage,
1573 const XrSwapchainImageBaseHeader *depthSwapchainImage)
1575 Q_Q(QQuick3DXrManager);
1577 auto *quickWindow = q->m_quickWindow;
1578 auto *renderControl = q->m_renderControl;
1580 const int arraySize = m_multiviewRendering ? m_swapchains[0].arraySize : 1;
1581 quickWindow->setRenderTarget(m_graphics->renderTarget(subImage,
1583 m_colorSwapchainFormat,
1586 depthSwapchainImage,
1587 m_depthSwapchainFormat));
1589 quickWindow->setGeometry(0,
1591 subImage.imageRect.extent.width,
1592 subImage.imageRect.extent.height);
1593 quickWindow->contentItem()->setSize(QSizeF(subImage.imageRect.extent.width,
1594 subImage.imageRect.extent.height));
1596 renderControl->polishItems();
1597 renderControl->beginFrame();
1598 renderControl->sync();
1599 renderControl->render();
1600 renderControl->endFrame();
1605 QRhiRenderTarget *rt = QQuickWindowPrivate::get(quickWindow)->activeCustomRhiRenderTarget();
1606 if (rt->resourceType() == QRhiResource::TextureRenderTarget &&
static_cast<QRhiTextureRenderTarget *>(rt)->description().colorAttachmentAt(0)->texture())
1607 emit q->frameReady();
1612 PFN_xrEnumerateColorSpacesFB pfnxrEnumerateColorSpacesFB = NULL;
1613 OpenXRHelpers::resolveXrFunction(m_instance,
"xrEnumerateColorSpacesFB", (PFN_xrVoidFunction*)(&pfnxrEnumerateColorSpacesFB));
1614 if (!pfnxrEnumerateColorSpacesFB)
1617 uint32_t colorSpaceCountOutput = 0;
1618 if (!checkXrResult(pfnxrEnumerateColorSpacesFB(m_session, 0, &colorSpaceCountOutput,
nullptr))) {
1619 qWarning(
"Failed to enumerate color spaces");
1623 XrColorSpaceFB* colorSpaces =
1624 (XrColorSpaceFB*)malloc(colorSpaceCountOutput *
sizeof(XrColorSpaceFB));
1626 if (!checkXrResult(pfnxrEnumerateColorSpacesFB(m_session, colorSpaceCountOutput, &colorSpaceCountOutput, colorSpaces))) {
1627 qWarning(
"Failed to enumerate color spaces");
1631 qCDebug(lcQuick3DXr,
"Supported color spaces:");
1632 for (uint32_t i = 0; i < colorSpaceCountOutput; i++) {
1633 qCDebug(lcQuick3DXr,
"%d:%d", i, colorSpaces[i]);
1636 const XrColorSpaceFB requestColorSpace = XR_COLOR_SPACE_QUEST_FB;
1638 PFN_xrSetColorSpaceFB pfnxrSetColorSpaceFB = NULL;
1639 OpenXRHelpers::resolveXrFunction(m_instance,
"xrSetColorSpaceFB", (PFN_xrVoidFunction*)(&pfnxrSetColorSpaceFB));
1641 if (!checkXrResult(pfnxrSetColorSpaceFB(m_session, requestColorSpace)))
1642 qWarning(
"Failed to set color space");
1649 PFN_xrEnumerateDisplayRefreshRatesFB pfnxrEnumerateDisplayRefreshRatesFB = NULL;
1650 OpenXRHelpers::resolveXrFunction(m_instance,
"xrEnumerateDisplayRefreshRatesFB", (PFN_xrVoidFunction*)(&pfnxrEnumerateDisplayRefreshRatesFB));
1651 if (!pfnxrEnumerateDisplayRefreshRatesFB)
1654 uint32_t numSupportedDisplayRefreshRates;
1655 QVector<
float> supportedDisplayRefreshRates;
1657 if (!checkXrResult(pfnxrEnumerateDisplayRefreshRatesFB(m_session, 0, &numSupportedDisplayRefreshRates,
nullptr))) {
1658 qWarning(
"Failed to enumerate display refresh rates");
1662 supportedDisplayRefreshRates.resize(numSupportedDisplayRefreshRates);
1664 if (!checkXrResult(pfnxrEnumerateDisplayRefreshRatesFB(
1666 numSupportedDisplayRefreshRates,
1667 &numSupportedDisplayRefreshRates,
1668 supportedDisplayRefreshRates.data())))
1670 qWarning(
"Failed to enumerate display refresh rates");
1674 qCDebug(lcQuick3DXr,
"Supported Refresh Rates:");
1675 for (uint32_t i = 0; i < numSupportedDisplayRefreshRates; i++) {
1676 qCDebug(lcQuick3DXr,
"%d:%f", i, supportedDisplayRefreshRates[i]);
1679 PFN_xrGetDisplayRefreshRateFB pfnGetDisplayRefreshRate;
1680 OpenXRHelpers::resolveXrFunction(m_instance,
"xrGetDisplayRefreshRateFB", (PFN_xrVoidFunction*)(&pfnGetDisplayRefreshRate));
1682 float currentDisplayRefreshRate = 0.0f;
1683 if (!checkXrResult(pfnGetDisplayRefreshRate(m_session, ¤tDisplayRefreshRate)))
1684 qWarning(
"Failed to get display refresh rate");
1686 qCDebug(lcQuick3DXr,
"Current System Display Refresh Rate: %f", currentDisplayRefreshRate);
1688 PFN_xrRequestDisplayRefreshRateFB pfnRequestDisplayRefreshRate;
1689 OpenXRHelpers::resolveXrFunction(m_instance,
"xrRequestDisplayRefreshRateFB", (PFN_xrVoidFunction*)(&pfnRequestDisplayRefreshRate));
1692 if (!checkXrResult(pfnRequestDisplayRefreshRate(m_session, 0.0f)))
1693 qWarning(
"Failed to request display refresh rate");
1695 qCDebug(lcQuick3DXr,
"Requesting system default display refresh rate");
1700 PFN_xrCreateFoveationProfileFB pfnCreateFoveationProfileFB;
1701 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreateFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnCreateFoveationProfileFB));
1702 if (!pfnCreateFoveationProfileFB)
1705 PFN_xrDestroyFoveationProfileFB pfnDestroyFoveationProfileFB;
1706 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyFoveationProfileFB", (PFN_xrVoidFunction*)(&pfnDestroyFoveationProfileFB));
1708 PFN_xrUpdateSwapchainFB pfnUpdateSwapchainFB;
1709 OpenXRHelpers::resolveXrFunction(m_instance,
"xrUpdateSwapchainFB", (PFN_xrVoidFunction*)(&pfnUpdateSwapchainFB));
1711 for (
auto swapchain : m_swapchains) {
1712 XrFoveationLevelProfileCreateInfoFB levelProfileCreateInfo = {};
1713 levelProfileCreateInfo.type = XR_TYPE_FOVEATION_LEVEL_PROFILE_CREATE_INFO_FB;
1714 levelProfileCreateInfo.level = m_foveationLevel;
1715 levelProfileCreateInfo.verticalOffset = 0;
1716 levelProfileCreateInfo.dynamic = XR_FOVEATION_DYNAMIC_DISABLED_FB;
1718 XrFoveationProfileCreateInfoFB profileCreateInfo = {};
1719 profileCreateInfo.type = XR_TYPE_FOVEATION_PROFILE_CREATE_INFO_FB;
1720 profileCreateInfo.next = &levelProfileCreateInfo;
1722 XrFoveationProfileFB foveationProfile;
1723 pfnCreateFoveationProfileFB(m_session, &profileCreateInfo, &foveationProfile);
1725 XrSwapchainStateFoveationFB foveationUpdateState = {};
1726 memset(&foveationUpdateState, 0,
sizeof(foveationUpdateState));
1727 foveationUpdateState.type = XR_TYPE_SWAPCHAIN_STATE_FOVEATION_FB;
1728 foveationUpdateState.profile = foveationProfile;
1730 XrResult updateSwapchainFBResult = OpenXRHelpers::safeCall(pfnUpdateSwapchainFB, swapchain.handle, (
const XrSwapchainStateBaseHeaderFB*)(&foveationUpdateState));
1731 if (updateSwapchainFBResult == XR_ERROR_FUNCTION_UNSUPPORTED)
1734 XrResult destroyFoveationProfileFBResult = OpenXRHelpers::safeCall(pfnDestroyFoveationProfileFB, foveationProfile);
1735 if (destroyFoveationProfileFBResult == XR_ERROR_FUNCTION_UNSUPPORTED)
1738 qCDebug(lcQuick3DXr,
"Fixed foveated rendering requested with level %d",
int(m_foveationLevel));
1747 Q_ASSERT(m_passthroughSupported && m_enablePassthrough);
1749 PFN_xrCreatePassthroughFB pfnXrCreatePassthroughFBX =
nullptr;
1750 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreatePassthroughFB", (PFN_xrVoidFunction*)(&pfnXrCreatePassthroughFBX));
1752 XrPassthroughCreateInfoFB passthroughCreateInfo{};
1753 passthroughCreateInfo.type = XR_TYPE_PASSTHROUGH_CREATE_INFO_FB;
1754 passthroughCreateInfo.flags = XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB;
1756 XrResult xrCreatePassthroughFBXResult = OpenXRHelpers::safeCall(pfnXrCreatePassthroughFBX, m_session,
static_cast<
const XrPassthroughCreateInfoFB*>(&passthroughCreateInfo), &m_passthroughFeature);
1757 if (!checkXrResult(xrCreatePassthroughFBXResult))
1758 qWarning(
"Failed to create passthrough object");
1763 PFN_xrDestroyPassthroughFB pfnXrDestroyPassthroughFBX =
nullptr;
1764 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyPassthroughFB", (PFN_xrVoidFunction*)(&pfnXrDestroyPassthroughFBX));
1766 XrResult xrDestroyPassthroughFBXResult = OpenXRHelpers::safeCall(pfnXrDestroyPassthroughFBX, m_passthroughFeature);
1767 if (!checkXrResult(xrDestroyPassthroughFBXResult))
1768 qWarning(
"Failed to destroy passthrough object");
1770 m_passthroughFeature = XR_NULL_HANDLE;
1775 PFN_xrPassthroughStartFB pfnXrPassthroughStartFBX =
nullptr;
1776 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughStartFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughStartFBX));
1778 XrResult xrPassthroughStartFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughStartFBX, m_passthroughFeature);
1779 if (!checkXrResult(xrPassthroughStartFBXResult))
1780 qWarning(
"Failed to start passthrough");
1785 PFN_xrPassthroughPauseFB pfnXrPassthroughPauseFBX =
nullptr;
1786 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughPauseFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughPauseFBX));
1788 XrResult xrPassthroughPauseFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughPauseFBX, m_passthroughFeature);
1789 if (!checkXrResult(xrPassthroughPauseFBXResult))
1790 qWarning(
"Failed to pause passthrough");
1795 PFN_xrCreatePassthroughLayerFB pfnXrCreatePassthroughLayerFBX =
nullptr;
1796 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreatePassthroughLayerFB", (PFN_xrVoidFunction*)(&pfnXrCreatePassthroughLayerFBX));
1798 XrPassthroughLayerCreateInfoFB layerCreateInfo{};
1799 layerCreateInfo.type = XR_TYPE_PASSTHROUGH_LAYER_CREATE_INFO_FB;
1800 layerCreateInfo.passthrough = m_passthroughFeature;
1801 layerCreateInfo.purpose = XR_PASSTHROUGH_LAYER_PURPOSE_RECONSTRUCTION_FB;
1802 if (m_enablePassthrough)
1803 layerCreateInfo.flags = XR_PASSTHROUGH_IS_RUNNING_AT_CREATION_BIT_FB;
1805 XrResult xrCreatePassthroughLayerFBXResult = OpenXRHelpers::safeCall(pfnXrCreatePassthroughLayerFBX, m_session,
static_cast<
const XrPassthroughLayerCreateInfoFB*>(&layerCreateInfo), &m_passthroughLayer);
1806 if (!checkXrResult(xrCreatePassthroughLayerFBXResult))
1807 qWarning(
"Failed to create passthrough layer");
1812 PFN_xrDestroyPassthroughLayerFB pfnXrDestroyPassthroughLayerFBX =
nullptr;
1813 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyPassthroughLayerFB", (PFN_xrVoidFunction*)(&pfnXrDestroyPassthroughLayerFBX));
1815 XrResult xrDestroyPassthroughLayerFBXResult = OpenXRHelpers::safeCall(pfnXrDestroyPassthroughLayerFBX, m_passthroughLayer);
1816 if (!checkXrResult(xrDestroyPassthroughLayerFBXResult))
1817 qWarning(
"Failed to destroy passthrough layer");
1819 m_passthroughLayer = XR_NULL_HANDLE;
1824 PFN_xrPassthroughLayerPauseFB pfnXrPassthroughLayerPauseFBX =
nullptr;
1825 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughLayerPauseFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughLayerPauseFBX));
1827 XrResult xrPassthroughLayerPauseFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughLayerPauseFBX, m_passthroughLayer);
1828 if (!checkXrResult(xrPassthroughLayerPauseFBXResult))
1829 qWarning(
"Failed to pause passthrough layer");
1834 PFN_xrPassthroughLayerResumeFB pfnXrPassthroughLayerResumeFBX =
nullptr;
1835 OpenXRHelpers::resolveXrFunction(m_instance,
"xrPassthroughLayerResumeFB", (PFN_xrVoidFunction*)(&pfnXrPassthroughLayerResumeFBX));
1837 XrResult xrPassthroughLayerResumeFBXResult = OpenXRHelpers::safeCall(pfnXrPassthroughLayerResumeFBX, m_passthroughLayer);
1838 if (!checkXrResult(xrPassthroughLayerResumeFBXResult))
1839 qWarning(
"Failed to resume passthrough layer");
1844 quint32 instanceExtensionCount;
1845 if (!checkXrResult(xrEnumerateInstanceExtensionProperties(layerName, 0, &instanceExtensionCount,
nullptr))) {
1846 qWarning(
"Failed to enumerate instance extension properties");
1850 QVector<XrExtensionProperties> extensions(instanceExtensionCount);
1851 for (XrExtensionProperties& extension : extensions) {
1852 extension.type = XR_TYPE_EXTENSION_PROPERTIES;
1853 extension.next =
nullptr;
1856 if (!checkXrResult(xrEnumerateInstanceExtensionProperties(layerName,
1857 quint32(extensions.size()),
1858 &instanceExtensionCount,
1859 extensions.data())))
1861 qWarning(
"Failed to enumerate instance extension properties");
1864 const QByteArray indentStr(indent,
' ');
1865 qCDebug(lcQuick3DXr,
"%sAvailable Extensions: (%d)", indentStr.data(), instanceExtensionCount);
1866 for (
const XrExtensionProperties& extension : extensions) {
1867 qCDebug(lcQuick3DXr,
"%s Name=%s Version=%d.%d.%d",
1869 extension.extensionName,
1870 XR_VERSION_MAJOR(extension.extensionVersion),
1871 XR_VERSION_MINOR(extension.extensionVersion),
1872 XR_VERSION_PATCH(extension.extensionVersion));
1879 if (!checkXrResult(xrEnumerateApiLayerProperties(0, &layerCount,
nullptr))) {
1880 qWarning(
"Failed to enumerate API layer properties");
1884 QVector<XrApiLayerProperties> layers(layerCount);
1885 for (XrApiLayerProperties& layer : layers) {
1886 layer.type = XR_TYPE_API_LAYER_PROPERTIES;
1887 layer.next =
nullptr;
1890 if (!checkXrResult(xrEnumerateApiLayerProperties(quint32(layers.size()), &layerCount, layers.data()))) {
1891 qWarning(
"Failed to enumerate API layer properties");
1895 qCDebug(lcQuick3DXr,
"Available Layers: (%d)", layerCount);
1896 for (
const XrApiLayerProperties& layer : layers) {
1897 qCDebug(lcQuick3DXr,
" Name=%s SpecVersion=%d.%d.%d LayerVersion=%d.%d.%d Description=%s",
1899 XR_VERSION_MAJOR(layer.specVersion),
1900 XR_VERSION_MINOR(layer.specVersion),
1901 XR_VERSION_PATCH(layer.specVersion),
1902 XR_VERSION_MAJOR(layer.layerVersion),
1903 XR_VERSION_MINOR(layer.layerVersion),
1904 XR_VERSION_PATCH(layer.layerVersion),
1906 checkXrExtensions(layer.layerName, 4);
1913 XrApplicationInfo appInfo;
1914 strcpy(appInfo.applicationName, QCoreApplication::applicationName().toUtf8());
1915 appInfo.applicationVersion = 7;
1916 strcpy(appInfo.engineName, QStringLiteral(
"Qt").toUtf8());
1917 appInfo.engineVersion = 6;
1922 appInfo.apiVersion = XR_MAKE_VERSION(1, 0, 34);
1925 uint32_t apiLayerCount = 0;
1926 xrEnumerateApiLayerProperties(0, &apiLayerCount,
nullptr);
1927 QVector<XrApiLayerProperties> apiLayerProperties(apiLayerCount);
1928 for (uint32_t i = 0; i < apiLayerCount; i++) {
1929 apiLayerProperties[i].type = XR_TYPE_API_LAYER_PROPERTIES;
1930 apiLayerProperties[i].next =
nullptr;
1932 xrEnumerateApiLayerProperties(apiLayerCount, &apiLayerCount, apiLayerProperties.data());
1935 QVector<
const char*> enabledApiLayers;
1940 const bool wantsValidationLayer = qEnvironmentVariableIntValue(
"QSG_RHI_DEBUG_LAYER");
1941 if (wantsValidationLayer) {
1942 if (isApiLayerSupported(
"XR_APILAYER_LUNARG_core_validation", apiLayerProperties))
1943 enabledApiLayers.append(
"XR_APILAYER_LUNARG_core_validation");
1945 qCDebug(lcQuick3DXr,
"OpenXR validation layer requested, but not available");
1948 qCDebug(lcQuick3DXr) <<
"Requesting to enable XR API layers:" << enabledApiLayers;
1950 m_enabledApiLayers.clear();
1951 for (
const char *layer : enabledApiLayers)
1952 m_enabledApiLayers.append(QString::fromLatin1(layer));
1955 uint32_t extensionCount = 0;
1956 xrEnumerateInstanceExtensionProperties(
nullptr, 0, &extensionCount,
nullptr);
1957 QVector<XrExtensionProperties> extensionProperties(extensionCount);
1958 for (uint32_t i = 0; i < extensionCount; i++) {
1961 extensionProperties[i].type = XR_TYPE_EXTENSION_PROPERTIES;
1962 extensionProperties[i].next =
nullptr;
1964 xrEnumerateInstanceExtensionProperties(
nullptr, extensionCount, &extensionCount, extensionProperties.data());
1966 QVector<
const char*> enabledExtensions;
1967 if (m_graphics->isExtensionSupported(extensionProperties))
1968 enabledExtensions.append(m_graphics->extensionName());
1970 if (isExtensionSupported(
"XR_EXT_debug_utils", extensionProperties))
1971 enabledExtensions.append(
"XR_EXT_debug_utils");
1973 if (isExtensionSupported(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME, extensionProperties))
1974 enabledExtensions.append(XR_EXT_PERFORMANCE_SETTINGS_EXTENSION_NAME);
1976 m_handtrackingExtensionSupported = isExtensionSupported(XR_EXT_HAND_TRACKING_EXTENSION_NAME, extensionProperties);
1977 if (m_handtrackingExtensionSupported)
1978 enabledExtensions.append(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
1980 m_compositionLayerDepthSupported = isExtensionSupported(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME, extensionProperties);
1981 if (m_compositionLayerDepthSupported) {
1984 enabledExtensions.append(XR_KHR_COMPOSITION_LAYER_DEPTH_EXTENSION_NAME);
1985 m_submitLayerDepth = qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_SUBMIT_DEPTH");
1986 if (m_submitLayerDepth)
1987 qCDebug(lcQuick3DXr,
"submitLayerDepth defaults to true due to env.var.");
1989 m_submitLayerDepth =
false;
1994 m_handtrackingAimExtensionSupported = isExtensionSupported(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME, extensionProperties);
1995 if (m_handtrackingAimExtensionSupported)
1996 enabledExtensions.append(XR_FB_HAND_TRACKING_AIM_EXTENSION_NAME);
1998 if (isExtensionSupported(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME, extensionProperties))
1999 enabledExtensions.append(XR_MSFT_HAND_INTERACTION_EXTENSION_NAME);
2001 if (isExtensionSupported(XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME, extensionProperties))
2002 enabledExtensions.append(XR_FB_HAND_TRACKING_MESH_EXTENSION_NAME);
2006 uint32_t passthroughSpecVersion = 0;
2007 if (isExtensionSupported(XR_FB_PASSTHROUGH_EXTENSION_NAME, extensionProperties, &passthroughSpecVersion)) {
2008 qCDebug(lcQuick3DXr,
"Passthrough extension is supported, spec version %u", passthroughSpecVersion);
2009 enabledExtensions.append(XR_FB_PASSTHROUGH_EXTENSION_NAME);
2011 qCDebug(lcQuick3DXr,
"Passthrough extension is NOT supported");
2014 if (isExtensionSupported(XR_FB_TRIANGLE_MESH_EXTENSION_NAME, extensionProperties))
2015 enabledExtensions.append(XR_FB_TRIANGLE_MESH_EXTENSION_NAME);
2017 m_displayRefreshRateExtensionSupported = isExtensionSupported(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME, extensionProperties);
2018 if (m_displayRefreshRateExtensionSupported)
2019 enabledExtensions.append(XR_FB_DISPLAY_REFRESH_RATE_EXTENSION_NAME);
2021 m_colorspaceExtensionSupported = isExtensionSupported(XR_FB_COLOR_SPACE_EXTENSION_NAME, extensionProperties);
2022 if (m_colorspaceExtensionSupported)
2023 enabledExtensions.append(XR_FB_COLOR_SPACE_EXTENSION_NAME);
2025 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME, extensionProperties))
2026 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_EXTENSION_NAME);
2028 m_foveationExtensionSupported = isExtensionSupported(XR_FB_FOVEATION_EXTENSION_NAME, extensionProperties);
2029 if (m_foveationExtensionSupported)
2030 enabledExtensions.append(XR_FB_FOVEATION_EXTENSION_NAME);
2032 if (isExtensionSupported(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME, extensionProperties))
2033 enabledExtensions.append(XR_FB_FOVEATION_CONFIGURATION_EXTENSION_NAME);
2035 if (m_spaceExtension) {
2036 const auto requiredExtensions = m_spaceExtension->requiredExtensions();
2037 bool isSupported =
true;
2038 for (
const auto extension : requiredExtensions) {
2039 isSupported = isExtensionSupported(extension, extensionProperties) && isSupported;
2043 m_spaceExtensionSupported = isSupported;
2045 enabledExtensions.append(requiredExtensions);
2049 if (isExtensionSupported(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME, extensionProperties))
2050 enabledExtensions.append(XR_KHR_ANDROID_THREAD_SETTINGS_EXTENSION_NAME);
2052 m_androidCreateInstanceExtensionSupported = isExtensionSupported(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME, extensionProperties);
2053 if (m_androidCreateInstanceExtensionSupported)
2054 enabledExtensions.append(XR_KHR_ANDROID_CREATE_INSTANCE_EXTENSION_NAME);
2056 auto graphicsAPI = QQuickWindow::graphicsApi();
2057 if (graphicsAPI == QSGRendererInterface::Vulkan) {
2058 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME, extensionProperties))
2059 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_VULKAN_EXTENSION_NAME);
2060 }
else if (graphicsAPI == QSGRendererInterface::OpenGL) {
2061 if (isExtensionSupported(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME, extensionProperties))
2062 enabledExtensions.append(XR_FB_SWAPCHAIN_UPDATE_STATE_OPENGL_ES_EXTENSION_NAME);
2066 qCDebug(lcQuick3DXr) <<
"Requesting to enable XR extensions:" << enabledExtensions;
2068 m_enabledExtensions.clear();
2069 for (
const char *extension : enabledExtensions)
2070 m_enabledExtensions.append(QString::fromLatin1(extension));
2073 XrInstanceCreateInfo xrInstanceInfo{};
2074 xrInstanceInfo.type = XR_TYPE_INSTANCE_CREATE_INFO;
2077 XrInstanceCreateInfoAndroidKHR xrInstanceCreateInfoAndroid {};
2078 if (m_androidCreateInstanceExtensionSupported) {
2079 xrInstanceCreateInfoAndroid.type = XR_TYPE_INSTANCE_CREATE_INFO_ANDROID_KHR;
2080 xrInstanceCreateInfoAndroid.applicationVM = m_javaVM;
2081 xrInstanceCreateInfoAndroid.applicationActivity = m_androidActivity.object();
2083 xrInstanceInfo.next = &xrInstanceCreateInfoAndroid;
2088 xrInstanceInfo.createFlags = 0;
2089 xrInstanceInfo.applicationInfo = appInfo;
2090 xrInstanceInfo.enabledApiLayerCount = enabledApiLayers.count();
2091 xrInstanceInfo.enabledApiLayerNames = enabledApiLayers.constData();
2092 xrInstanceInfo.enabledExtensionCount = enabledExtensions.count();
2093 xrInstanceInfo.enabledExtensionNames = enabledExtensions.constData();
2095 return xrCreateInstance(&xrInstanceInfo, &m_instance);
2100 Q_ASSERT(m_instance != XR_NULL_HANDLE);
2101 XrInstanceProperties instanceProperties{};
2102 instanceProperties.type = XR_TYPE_INSTANCE_PROPERTIES;
2103 if (!checkXrResult(xrGetInstanceProperties(m_instance, &instanceProperties))) {
2104 qWarning(
"Failed to get instance properties");
2108 m_runtimeName = QString::fromUtf8(instanceProperties.runtimeName);
2109 m_runtimeVersion = QVersionNumber(XR_VERSION_MAJOR(instanceProperties.runtimeVersion),
2110 XR_VERSION_MINOR(instanceProperties.runtimeVersion),
2111 XR_VERSION_PATCH(instanceProperties.runtimeVersion));
2113 qCDebug(lcQuick3DXr,
"Instance RuntimeName=%s RuntimeVersion=%d.%d.%d",
2114 qPrintable(m_runtimeName),
2115 m_runtimeVersion.majorVersion(),
2116 m_runtimeVersion.minorVersion(),
2117 m_runtimeVersion.microVersion());
2122 if (!m_enabledExtensions.contains(QString::fromUtf8(
"XR_EXT_debug_utils"))) {
2123 qCDebug(lcQuick3DXr,
"No debug utils extension, message redirection not set up");
2127#ifdef XR_EXT_debug_utils
2128 PFN_xrCreateDebugUtilsMessengerEXT xrCreateDebugUtilsMessengerEXT =
nullptr;
2129 OpenXRHelpers::resolveXrFunction(m_instance,
"xrCreateDebugUtilsMessengerEXT",
reinterpret_cast<PFN_xrVoidFunction *>(&xrCreateDebugUtilsMessengerEXT));
2130 if (!xrCreateDebugUtilsMessengerEXT)
2133 OpenXRHelpers::resolveXrFunction(m_instance,
"xrDestroyDebugUtilsMessengerEXT",
reinterpret_cast<PFN_xrVoidFunction *>(&m_xrDestroyDebugUtilsMessengerEXT));
2135 XrDebugUtilsMessengerCreateInfoEXT messengerInfo = {};
2136 messengerInfo.type = XR_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
2137 messengerInfo.messageSeverities = XR_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT
2138 | XR_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
2139 messengerInfo.messageTypes = XR_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT
2140 | XR_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT
2141 | XR_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT
2142 | XR_DEBUG_UTILS_MESSAGE_TYPE_CONFORMANCE_BIT_EXT;
2143 messengerInfo.userCallback = defaultDebugCallbackFunc;
2144 messengerInfo.userData =
this;
2146 XrResult err = xrCreateDebugUtilsMessengerEXT(m_instance, &messengerInfo, &m_debugMessenger);
2147 if (!checkXrResult(err))
2148 qWarning(
"Quick 3D XR: Failed to create debug report callback, OpenXR messages will not get redirected (%d)", err);
2154 Q_ASSERT(m_instance != XR_NULL_HANDLE);
2155 Q_ASSERT(m_systemId == XR_NULL_SYSTEM_ID);
2157 XrSystemGetInfo hmdInfo{};
2158 hmdInfo.type = XR_TYPE_SYSTEM_GET_INFO;
2159 hmdInfo.next =
nullptr;
2160 hmdInfo.formFactor = m_formFactor;
2162 const XrResult result = xrGetSystem(m_instance, &hmdInfo, &m_systemId);
2163 const bool success = checkXrResult(result);
2169 checkViewConfiguration();
2176 quint32 viewConfigTypeCount;
2177 if (!checkXrResult(xrEnumerateViewConfigurations(m_instance,
2180 &viewConfigTypeCount,
2183 qWarning(
"Failed to enumerate view configurations");
2186 QVector<XrViewConfigurationType> viewConfigTypes(viewConfigTypeCount);
2187 if (!checkXrResult(xrEnumerateViewConfigurations(m_instance,
2189 viewConfigTypeCount,
2190 &viewConfigTypeCount,
2191 viewConfigTypes.data())))
2193 qWarning(
"Failed to enumerate view configurations");
2197 qCDebug(lcQuick3DXr,
"Available View Configuration Types: (%d)", viewConfigTypeCount);
2198 for (XrViewConfigurationType viewConfigType : viewConfigTypes) {
2199 qCDebug(lcQuick3DXr,
" View Configuration Type: %s %s", to_string(viewConfigType), viewConfigType == m_viewConfigType ?
"(Selected)" :
"");
2200 XrViewConfigurationProperties viewConfigProperties{};
2201 viewConfigProperties.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
2202 if (!checkXrResult(xrGetViewConfigurationProperties(m_instance,
2205 &viewConfigProperties)))
2207 qWarning(
"Failed to get view configuration properties");
2211 qCDebug(lcQuick3DXr,
" View configuration FovMutable=%s", viewConfigProperties.fovMutable == XR_TRUE ?
"True" :
"False");
2214 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
2221 qWarning(
"Failed to enumerate configuration views");
2225 if (viewCount > 0) {
2226 QVector<XrViewConfigurationView> views(viewCount, {XR_TYPE_VIEW_CONFIGURATION_VIEW,
nullptr, 0, 0, 0, 0, 0, 0});
2227 if (!checkXrResult(xrEnumerateViewConfigurationViews(m_instance,
2234 qWarning(
"Failed to enumerate configuration views");
2238 for (
int i = 0; i < views.size(); ++i) {
2239 const XrViewConfigurationView& view = views[i];
2240 qCDebug(lcQuick3DXr,
" View [%d]: Recommended Width=%d Height=%d SampleCount=%d",
2242 view.recommendedImageRectWidth,
2243 view.recommendedImageRectHeight,
2244 view.recommendedSwapchainSampleCount);
2245 qCDebug(lcQuick3DXr,
" View [%d]: Maximum Width=%d Height=%d SampleCount=%d",
2247 view.maxImageRectWidth,
2248 view.maxImageRectHeight,
2249 view.maxSwapchainSampleCount);
2252 qCDebug(lcQuick3DXr,
"Empty view configuration type");
2254 checkEnvironmentBlendMode(viewConfigType);
2260 return OpenXRHelpers::checkXrResult(result, m_instance);
2266 if (!checkXrResult(xrEnumerateEnvironmentBlendModes(m_instance,
2273 qWarning(
"Failed to enumerate blend modes");
2277 qCDebug(lcQuick3DXr,
"Available Environment Blend Mode count : (%d)", count);
2279 QVector<XrEnvironmentBlendMode> blendModes(count);
2280 if (!checkXrResult(xrEnumerateEnvironmentBlendModes(m_instance,
2285 blendModes.data())))
2287 qWarning(
"Failed to enumerate blend modes");
2291 bool blendModeFound =
false;
2292 for (XrEnvironmentBlendMode mode : blendModes) {
2293 const bool blendModeMatch = (mode == m_environmentBlendMode);
2294 qCDebug(lcQuick3DXr,
"Environment Blend Mode (%s) : %s", to_string(mode), blendModeMatch ?
"(Selected)" :
"");
2295 blendModeFound |= blendModeMatch;
2297 if (!blendModeFound)
2298 qWarning(
"No matching environment blend mode found");
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 QtQuick3DXr::ReferenceSpace getReferenceSpaceType(XrReferenceSpaceType referenceSpace)
static bool isExtensionSupported(const char *extensionName, const QVector< XrExtensionProperties > &instanceExtensionProperties, uint32_t *extensionVersion=nullptr)