10#include "../qquick3dxrinputmanager_p.h"
11#include "../qquick3dxranimationdriver_p.h"
13#include <QtQuick3D/private/qquick3dviewport_p.h>
14#include <QtQuick3D/private/qquick3dnode_p_p.h>
16#include <QtQuick3DUtils/private/qssgassert_p.h>
18#include <QQuickGraphicsDevice>
21#include <CompositorServices/CompositorServices.h>
22#include <QtGui/qguiapplication_platform.h>
24#include <QtCore/qoperatingsystemversion.h>
25#include <QtCore/qloggingcategory.h>
27#include <TargetConditionals.h>
31Q_DECLARE_LOGGING_CATEGORY(lcQuick3DXr);
38 static bool foveationDisabled = qEnvironmentVariableIntValue(
"QT_QUICK3D_XR_DISABLE_FOVEATION") != 0;
39 return foveationDisabled;
49 m_xrManager =
nullptr;
50 [m_layerRenderer release];
51 m_layerRenderer =
nullptr;
52 m_worldTrackingProvider =
nullptr;
53 m_arSession =
nullptr;
54 m_initialized =
false;
68 static bool supportsLayoutType(cp_layer_renderer_capabilities_t capabilities, cp_layer_renderer_layout layout)
70 const size_t layoutCount = cp_layer_renderer_capabilities_supported_layouts_count(capabilities, cp_supported_layouts_options_none);
72 for (size_t i = 0; i < layoutCount && !found; ++i)
73 found = (layout == cp_layer_renderer_capabilities_supported_layout(capabilities, cp_supported_layouts_options_none, i));
78 void configure(cp_layer_renderer_capabilities_t capabilities, cp_layer_renderer_configuration_t configuration)
const override
86 m_multiviewSupported = supportsLayoutType(capabilities, cp_layer_renderer_layout_layered);
87 m_multiviewEnabled = m_multiviewEnabled && m_multiviewSupported;
90 m_foveationSupported = cp_layer_renderer_capabilities_supports_foveation(capabilities);
97 cp_layer_renderer_layout textureLayout = m_multiviewEnabled ? cp_layer_renderer_layout_layered
98 : cp_layer_renderer_layout_dedicated;
100 cp_layer_renderer_configuration_set_layout(configuration, textureLayout);
101 cp_layer_renderer_configuration_set_foveation_enabled(configuration, m_foveationEnabled);
102 cp_layer_renderer_configuration_set_color_format(configuration, MTLPixelFormatRGBA16Float);
103 simd_float2 depthRange = cp_layer_renderer_configuration_get_default_depth_range(configuration);
105 m_depthRange[0] = depthRange.y;
106 m_depthRange[1] = depthRange.x;
108 qCDebug(lcQuick3DXr) <<
"Configuring with the following settings:"
109 <<
"\n\tMultiview supported: " << m_multiviewSupported
110 <<
"\n\tMultiview enabled: " << m_multiviewEnabled
111 <<
"\n\tFoveation supported: " << m_foveationSupported
112 <<
"\n\tFoveation enabled: " << m_foveationEnabled
113 <<
"\n\tDepth Range: " << m_depthRange[0] <<
" to: " << m_depthRange[1];
116 void render(cp_layer_renderer_t renderer)
override
118 if (m_layerRenderer != renderer) {
119 m_layerRenderer = renderer;
120 emit layerRendererChanged();
123 if (m_layerRenderer) {
128 [m_layerRenderer retain];
130 emit layerRendererReady();
138 m_xrManager->processSpatialEvents(events);
150 return m_layerRenderer;
155 near = m_depthRange[0];
156 far = m_depthRange[1];
162 Q_ASSERT(qApp->thread() == QThread::currentThread());
163 QSSG_ASSERT(!m_initialized,
return);
165 m_xrManager = xrManager;
166 runWorldTrackingARSession();
167 m_initialized =
true;
177 Q_ASSERT(qApp->thread() == QThread::currentThread());
182 qCDebug(lcQuick3DXr,
"Stopping AR session");
186 ar_session_set_data_provider_state_change_handler_f(m_arSession, dispatch_get_main_queue(),
this, &onArStateChanged);
187 ar_session_stop(m_arSession);
188 m_arSession =
nullptr;
196 return m_waitCondition.wait(&m_mutex);
201 QSSG_ASSERT(mngr !=
nullptr,
return);
203 qCDebug(lcQuick3DXr) <<
"Destroying compositor layer";
205 if (
auto *visionOSApplicaton = qGuiApp->nativeInterface<QNativeInterface::QVisionOSApplication>())
206 visionOSApplicaton->setImmersiveSpaceCompositorLayer(
nullptr);
216 auto *d = QQuickWindowPrivate::get(window);
217 d->cleanupNodesOnShutdown();
218 mngr->releaseResources();
219 if (
auto *rc = d->renderControl)
225 compositorLayer->deleteLater();
243 qCDebug(lcQuick3DXr) <<
"Teardown in progress, skipping event handling";
246 if (event->type() == QEvent::DeferredDelete)
248 return QObject::event(event);
251 switch (
static_cast<
Event>(event->type())) {
254 const bool success = renderFrame(locker);
259 qCDebug(lcQuick3DXr) <<
"Waking up the GUI thread, rendering returned early...";
260 m_xrManager->m_syncDone =
false;
261 m_waitCondition.wakeOne();
277 return QObject::event(event);
284 static void onArStateChanged(
void *context,
285 ar_data_providers_t data_providers,
286 ar_data_provider_state_t new_state,
288 ar_data_provider_t failed_data_provider)
291 Q_UNUSED(data_providers);
293 Q_UNUSED(failed_data_provider);
300 QSSG_ASSERT_X(that->m_arSession !=
nullptr,
"AR session is not running, skipping state change!",
return);
302 const auto oldState = that->m_arTrackingState;
304 case ar_data_provider_state_initialized:
307 case ar_data_provider_state_running:
310 case ar_data_provider_state_paused:
313 case ar_data_provider_state_stopped:
319 if (oldState != that->m_arTrackingState) {
321 emit that->arStateChanged(that->m_arTrackingState);
325 enum class RenderStateAction
331 template<RenderStateAction Action = RenderStateAction::WaitUntilRunning>
332 void checkRenderState()
334 QSSG_ASSERT(m_layerRenderer !=
nullptr,
return);
336 const auto oldState = m_renderState;
337 switch (cp_layer_renderer_get_state(m_layerRenderer)) {
338 case cp_layer_renderer_state_paused:
339 m_renderState = QQuick3DXrManagerPrivate::RenderState::Paused;
341 case cp_layer_renderer_state_running:
342 m_renderState = QQuick3DXrManagerPrivate::RenderState::Running;
344 case cp_layer_renderer_state_invalidated:
345 m_renderState = QQuick3DXrManagerPrivate::RenderState::Invalidated;
349 if (oldState != m_renderState)
350 emit renderStateChanged(m_renderState);
352 if (m_renderState == QQuick3DXrManagerPrivate::RenderState::Paused) {
353 if constexpr (Action == RenderStateAction::WaitUntilRunning) {
354 qCDebug(lcQuick3DXr) <<
"Waiting for rendering to resume...";
355 cp_layer_renderer_wait_until_running(m_layerRenderer);
356 QCoreApplication::postEvent(
this,
new QEvent(asQEvent(CompositorLayer::Event::Pulse)));
361 ar_device_anchor_t createPoseForTiming(cp_frame_timing_t timing)
363 QSSG_ASSERT(m_worldTrackingProvider !=
nullptr,
return nullptr);
365 ar_device_anchor_t outAnchor = ar_device_anchor_create();
366 cp_time_t presentationTime = cp_frame_timing_get_presentation_time(timing);
367 CFTimeInterval queryTime = cp_time_to_cf_time_interval(presentationTime);
368 ar_device_anchor_query_status_t status = ar_world_tracking_provider_query_device_anchor_at_timestamp(m_worldTrackingProvider, queryTime, outAnchor);
369 if (status != ar_device_anchor_query_status_success) {
370 NSLog(@
"Failed to get estimated pose from world tracking provider for presentation timestamp %0.3f", queryTime);
375 void runWorldTrackingARSession()
379 ar_world_tracking_configuration_t worldTrackingConfiguration = ar_world_tracking_configuration_create();
380 m_worldTrackingProvider = ar_world_tracking_provider_create(worldTrackingConfiguration);
382 ar_data_providers_t dataProviders = ar_data_providers_create();
383 ar_data_providers_add_data_provider(dataProviders, m_worldTrackingProvider);
390 if (QSSG_GUARD_X(inputManager !=
nullptr,
"No InputManager available!")) {
392 if (QSSG_GUARD(pim !=
nullptr))
396 if (QSSG_GUARD_X(anchorManager !=
nullptr,
"No AnchorManager available!"))
397 QQuick3DXrManagerPrivate::prepareAnchorManager(anchorManager, dataProviders);
399 m_arSession = ar_session_create();
400 ar_session_set_data_provider_state_change_handler_f(m_arSession, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
this, &onArStateChanged);
401 ar_session_run(m_arSession, dataProviders);
410 qCDebug(lcQuick3DXr,
"Pausing rendering");
415 qCDebug(lcQuick3DXr,
"Cleaning up");
417 m_xrManager->releaseResources();
422 Q_ASSERT(locker.isLocked());
425 if (m_renderState != QQuick3DXrManagerPrivate::RenderState::Running) {
426 qCDebug(lcQuick3DXr,
"Rendering is not running, skipping frame rendering!");
434 qCDebug(lcQuick3DXr,
"AR tracking is not running, skipping frame rendering!");
442 return m_xrManager->renderFrameImpl(locker, m_waitCondition);
445 ar_world_tracking_provider_t worldTrackingProvider()
const
447 return m_worldTrackingProvider;
451 mutable QMutex m_mutex;
452 QWaitCondition m_waitCondition;
454 mutable QMutex m_compositorLayerMtx;
457 mutable QMutex m_arSessionMtx;
461 cp_layer_renderer_t m_layerRenderer =
nullptr;
462 ar_world_tracking_provider_t m_worldTrackingProvider =
nullptr;
463 ar_session_t m_arSession =
nullptr;
464 mutable float m_depthRange[2] {1.0f, 10000.0f};
467 bool m_initialized =
false;
468 bool m_teardown =
false;
469 mutable bool m_multiviewSupported =
true;
470 mutable bool m_multiviewEnabled =
true;
471 mutable bool m_foveationSupported =
true;
472 mutable bool m_foveationEnabled =
true;
483void QQuick3DXrManagerPrivate::updateCameraImp(simd_float4x4 headTransform, cp_drawable_t drawable, QQuick3DXrOrigin *xrOrigin,
int i)
485 cp_view_t view = cp_drawable_get_view(drawable, i);
486 simd_float2 depth_range = cp_drawable_get_depth_range(drawable);
487 const float clipNear = depth_range[1];
488 const float clipFar = depth_range[0];
490 xrOrigin->eyeCamera(i)->setClipNear(clipNear);
491 xrOrigin->eyeCamera(i)->setClipFar(clipFar);
493 simd_float4x4 projection = cp_drawable_compute_projection(drawable, cp_axis_direction_convention_right_up_forward, i);
494 QMatrix4x4 proj{projection.columns[0].x, projection.columns[1].x, projection.columns[2].x, projection.columns[3].x,
495 projection.columns[0].y, projection.columns[1].y, projection.columns[2].y, projection.columns[3].y,
496 projection.columns[0].z, projection.columns[1].z, projection.columns[2].z, projection.columns[3].z,
497 projection.columns[0].w, projection.columns[1].w, projection.columns[2].w, projection.columns[3].w};
498 xrOrigin->eyeCamera(i)->setProjection(proj);
500 simd_float4x4 localEyeTransform = cp_view_get_transform(view);
501 simd_float4x4 eyeCameraTransform = simd_mul(headTransform, localEyeTransform);
503 QMatrix4x4 transform{eyeCameraTransform.columns[0].x, eyeCameraTransform.columns[1].x, eyeCameraTransform.columns[2].x, eyeCameraTransform.columns[3].x * 100,
504 eyeCameraTransform.columns[0].y, eyeCameraTransform.columns[1].y, eyeCameraTransform.columns[2].y, eyeCameraTransform.columns[3].y * 100,
505 eyeCameraTransform.columns[0].z, eyeCameraTransform.columns[1].z, eyeCameraTransform.columns[2].z, eyeCameraTransform.columns[3].z * 100,
506 0.0f, 0.0f, 0.0f, 1.0f};
507 QQuick3DNodePrivate::get(xrOrigin->eyeCamera(i))->setLocalTransform(transform);
510void QQuick3DXrManagerPrivate::updateCamera(QQuick3DViewport *xrViewport, simd_float4x4 headTransform, cp_drawable_t drawable, QQuick3DXrOrigin *xrOrigin,
int i)
512 updateCameraImp(headTransform, drawable, xrOrigin, i);
513 xrViewport->setCamera(xrOrigin->eyeCamera(i));
516void QQuick3DXrManagerPrivate::updateCameraMultiview(QQuick3DViewport *xrViewport, simd_float4x4 headTransform, cp_drawable_t drawable, QQuick3DXrOrigin *xrOrigin)
518 QQuick3DCamera *cameras[2] {xrOrigin->eyeCamera(0), xrOrigin->eyeCamera(1)};
520 for (
int i = 0; i < 2; ++i)
521 updateCameraImp(headTransform, drawable, xrOrigin, i);
523 xrViewport->setMultiViewCameras(cameras);
538 QSSG_ASSERT(manager !=
nullptr,
return nullptr);
539 return manager->d_func();
544 Q_Q(QQuick3DXrManager);
549 if (!m_compositorLayer) {
550 m_compositorLayer = s_compositorLayer->instance;
551 if (!m_compositorLayer) {
553 s_compositorLayer->instance = m_compositorLayer;
558 m_inputManager = QQuick3DXrInputManager::instance();
559 if (!m_anchorManager)
560 m_anchorManager = QQuick3DXrAnchorManager::instance();
564 if (
auto *visionOSApplicaton = qGuiApp->nativeInterface<QNativeInterface::QVisionOSApplication>()) {
565 visionOSApplicaton->setImmersiveSpaceCompositorLayer(m_compositorLayer);
567 QObject::connect(m_compositorLayer, &CompositorLayer::layerRendererReady, q, &QQuick3DXrManager::initialized, Qt::ConnectionType(Qt::SingleShotConnection | Qt::QueuedConnection));
568 QObject::connect(m_compositorLayer, &CompositorLayer::renderStateChanged, q, [q](QQuick3DXrManagerPrivate::RenderState state) {
570 case QQuick3DXrManagerPrivate::RenderState::Uninitialized:
571 qCDebug(lcQuick3DXr,
"Render state: Uninitialized");
572 QQuick3DXrManagerPrivate::get(q)->m_running =
false;
574 case QQuick3DXrManagerPrivate::RenderState::Running:
575 qCDebug(lcQuick3DXr,
"Render state: Running");
576 QQuick3DXrManagerPrivate::get(q)->m_running =
true;
577 QCoreApplication::postEvent(q,
new QEvent(QEvent::UpdateRequest));
579 case QQuick3DXrManagerPrivate::RenderState::Invalidated:
580 qCDebug(lcQuick3DXr,
"Render state: Invalidated");
581 QQuick3DXrManagerPrivate::get(q)->m_running =
false;
582 emit q->sessionEnded();
584 case QQuick3DXrManagerPrivate::RenderState::Paused:
585 QQuick3DXrManagerPrivate::get(q)->m_running =
false;
586 qCDebug(lcQuick3DXr,
"Render state: Paused");
589 }, Qt::DirectConnection);
591 QObject::connect(m_compositorLayer, &CompositorLayer::arStateChanged, q, [q](QQuick3DXrManagerPrivate::ArTrackingState state) {
593 case QQuick3DXrManagerPrivate::ArTrackingState::Uninitialized:
594 qCDebug(lcQuick3DXr,
"AR state: Uninitialized");
595 QQuick3DXrManagerPrivate::get(q)->m_arRunning =
false;
597 case QQuick3DXrManagerPrivate::ArTrackingState::Initialized:
598 qCDebug(lcQuick3DXr,
"AR state: Initialized");
599 QQuick3DXrManagerPrivate::get(q)->m_arRunning =
false;
601 case QQuick3DXrManagerPrivate::ArTrackingState::Running:
602 qCDebug(lcQuick3DXr,
"AR state: Running");
603 QQuick3DXrManagerPrivate::get(q)->m_arRunning =
true;
604 QCoreApplication::postEvent(q,
new QEvent(QEvent::UpdateRequest));
606 case QQuick3DXrManagerPrivate::ArTrackingState::Paused:
607 qCDebug(lcQuick3DXr,
"AR state: Paused");
608 QQuick3DXrManagerPrivate::get(q)->m_arRunning =
false;
610 case QQuick3DXrManagerPrivate::ArTrackingState::Stopped:
611 qCDebug(lcQuick3DXr,
"AR state: Stopped");
612 QQuick3DXrManagerPrivate::get(q)->m_arRunning =
false;
615 }, Qt::DirectConnection);
628 qWarning(
"QQuick3DXrManagerPrivate: Window is null!");
632 QSSG_ASSERT_X(m_compositorLayer !=
nullptr,
"No composition layer!",
return);
634 cp_layer_renderer_t renderer = m_compositorLayer->layerRenderer();
636 qWarning(
"QQuick3DXrManagerPrivate: Layer renderer is not available.");
640 auto device = cp_layer_renderer_get_device(renderer);
641 auto commandQueue = [device newCommandQueue];
643 auto qqGraphicsDevice = QQuickGraphicsDevice::fromDeviceAndCommandQueue(
static_cast<MTLDevice*>(device),
static_cast<MTLCommandQueue *>(commandQueue));
645 window->setGraphicsDevice(qqGraphicsDevice);
652 m_isGraphicsInitialized =
true;
653 return m_isGraphicsInitialized;
658 return m_compositorLayer && (m_compositorLayer->layerRenderer() !=
nullptr);
663 return m_isGraphicsInitialized;
668 QSSG_ASSERT(window !=
nullptr && m_compositorLayer !=
nullptr,
return false);
671 if (!m_renderThread) {
672 m_renderThread =
new QThread;
673 m_renderThread->setObjectName(QLatin1StringView(s_renderThreadName));
674 m_renderThread->start();
677 if (m_compositorLayer->thread() != m_renderThread)
678 m_compositorLayer->moveToThread(m_renderThread);
680 Q_ASSERT(m_renderThread !=
nullptr);
681 QQuickWindowPrivate::get(window)->renderControl->prepareThread(m_renderThread);
697 Q_Q(QQuick3DXrManager);
699 qCDebug(lcQuick3DXr) <<
"Tearing down XR session";
702 if (m_compositorLayer)
703 locker = QMutexLocker<QMutex>{ &m_compositorLayer
->renderLock() };
708 QQuick3DXrInputManagerPrivate::get(m_inputManager)->teardown();
711 m_anchorManager->teardown();
713 if (m_compositorLayer) {
721 Qt::ConnectionType connection = (m_compositorLayer->thread() == QThread::currentThread())
722 ? Qt::DirectConnection : Qt::BlockingQueuedConnection;
723 QMetaObject::invokeMethod(m_compositorLayer, &CompositorLayer::destroy, connection,
this, q->m_quickWindow, m_compositorLayer);
724 m_compositorLayer =
nullptr;
727 if (m_renderThread) {
728 m_renderThread->quit();
729 m_renderThread->wait();
730 delete m_renderThread;
731 m_renderThread =
nullptr;
738 qCWarning(lcQuick3DXr) <<
"Changing multiview rendering is not supported at runtime on visionOS!";
743 return m_multiviewRenderingEnabled;
749 qCWarning(lcQuick3DXr) <<
"Changing passthrough is not supported at runtime on visionOS!";
756 return QtQuick3DXr::ReferenceSpace::ReferenceSpaceLocalFloor;
761 Q_UNUSED(newReferenceSpace);
762 qCWarning(lcQuick3DXr) <<
"Changing reference space is not supported at runtime on visionOS!";
768 qCWarning(lcQuick3DXr,
"Depth submission is required on visionOS");
773 Q_Q(QQuick3DXrManager);
776 QMutexLocker<QMutex> locker { &m_compositorLayer->renderLock() };
778 if (!m_running || !m_arRunning || !m_isGraphicsInitialized) {
779 qCDebug(lcQuick3DXr,
"Not running, skipping update");
785 q->m_renderControl->polishItems();
787 QCoreApplication::postEvent(m_compositorLayer,
new QEvent(CompositorLayer::asQEvent(CompositorLayer::Event::Render)));
792 QQuick3DXrAnimationDriver *animationDriver = q->m_animationDriver;
794 if (Q_LIKELY(waitCompleted && m_syncDone && animationDriver)) {
795 animationDriver->setStep(m_nextStepSize);
796 animationDriver->advance();
798 qCDebug(lcQuick3DXr) <<
"Failed to wait for sync to complete" <<
"\nWaitCompleted:" << waitCompleted <<
"\nsyncDone" << m_syncDone;
801 [[maybe_unused]]
bool ret = m_compositorLayer->renderFrame(locker);
804 QCoreApplication::postEvent(q,
new QEvent(QEvent::UpdateRequest));
814 Q_Q(QQuick3DXrManager);
815 QSSG_ASSERT(q->m_vrViewport !=
nullptr,
return);
816 QQuick3DXrInputManagerPrivate::processSpatialEvents(*q->m_vrViewport, events);
821 anchorManager->prepareAnchorManager(dataProviders);
826 anchorManager->initAnchorManager();
837 qCWarning(lcQuick3DXr) <<
"Changing sample count is not supported on visionOS!";
842 return QStringLiteral(
"visionOS");
847 static const auto versionNumber = QOperatingSystemVersion::current().version();
848 return versionNumber;
858 if (QRhiSwapChain *swapchain = window->swapChain()) {
859 swapchain->setShadingRateMap(srm);
860 if (!m_srmRenderPassDesc) {
861 qCDebug(lcQuick3DXr) <<
"Creating render pass descriptor suitable for shading rate map use";
862 m_srmRenderPassDesc = swapchain->newCompatibleRenderPassDescriptor();
863 swapchain->setRenderPassDescriptor(m_srmRenderPassDesc);
866 QSGRendererInterface *rif = window->rendererInterface();
867 QRhiTextureRenderTarget *rt =
static_cast<QRhiTextureRenderTarget *>(rif->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget));
868 if (QSSG_GUARD_X(rt,
"No render target!")) {
870 desc.setShadingRateMap(srm);
871 rt->setDescription(desc);
872 if (!m_srmRenderPassDesc) {
873 qCDebug(lcQuick3DXr) <<
"Creating render pass descriptor suitable for shading rate map use";
874 QRhiRenderPassDescriptor *rpd = rt->renderPassDescriptor();
875 m_srmRenderPassDesc = rpd->newCompatibleRenderPassDescriptor();
876 rt->setRenderPassDescriptor(m_srmRenderPassDesc);
885 qCDebug(lcQuick3DXr) <<
"Releasing resources";
886 Q_ASSERT((m_renderThread ==
nullptr) || QThread::currentThread() == m_renderThread);
887 delete m_srmRenderPassDesc;
888 m_srmRenderPassDesc =
nullptr;
889 delete m_rhiDepthTexture;
890 m_rhiDepthTexture =
nullptr;
891 for (size_t i = 0, end = std::size(m_srm); i < end; ++i) {
899 Q_Q(QQuick3DXrManager);
902 QQuickWindow *window = q->m_quickWindow;
903 QQuickRenderControl *renderControl = q->m_renderControl;
904 QQuick3DXrOrigin *xrOrigin = q->m_xrOrigin;
905 QQuick3DViewport *xrViewport = q->m_vrViewport;
906 QQuick3DXrAnimationDriver *animationDriver = q->m_animationDriver;
908 QSSG_ASSERT_X(window && renderControl && xrViewport && xrOrigin && animationDriver,
"Invalid state, rendering aborted",
return false);
912 Q_ASSERT(!multiviewRenderingEnabled || QThread::currentThread() != window->thread());
914 auto layerRenderer = m_compositorLayer->layerRenderer();
915 cp_frame_t frame = cp_layer_renderer_query_next_frame(layerRenderer);
916 if (Q_UNLIKELY(frame ==
nullptr)) {
917 qWarning(
"Failed to get next frame");
921 cp_frame_timing_t timing = cp_frame_predict_timing(frame);
922 if (Q_UNLIKELY(timing ==
nullptr)) {
923 qWarning(
"Failed to get timing for frame");
927 cp_frame_start_update(frame);
929 cp_frame_end_update(frame);
931 cp_time_t optimalInputTime = cp_frame_timing_get_optimal_input_time(timing);
932 cp_time_wait_until(optimalInputTime);
934 cp_frame_start_submission(frame);
935 cp_drawable_t drawable = cp_frame_query_drawable(frame);
936 if (Q_UNLIKELY(drawable ==
nullptr)) {
937 qWarning(
"Failed to get drawable for frame");
941 cp_frame_timing_t actualTiming = cp_drawable_get_frame_timing(drawable);
942 ar_device_anchor_t anchor = m_compositorLayer->createPoseForTiming(actualTiming);
943 cp_drawable_set_device_anchor(drawable, anchor);
946 simd_float4x4 headTransform = ar_anchor_get_origin_from_anchor_transform(anchor);
949 QMatrix4x4 qtHeadTransform{headTransform.columns[0].x, headTransform.columns[1].x, headTransform.columns[2].x, headTransform.columns[3].x * 100,
950 headTransform.columns[0].y, headTransform.columns[1].y, headTransform.columns[2].y, headTransform.columns[3].y * 100,
951 headTransform.columns[0].z, headTransform.columns[1].z, headTransform.columns[2].z, headTransform.columns[3].z * 100,
952 0.0f, 0.0f, 0.0f, 1.0f};
953 xrOrigin->updateTrackedCamera(qtHeadTransform);
956 if (QSSG_GUARD(m_inputManager !=
nullptr))
957 QQuick3DXrInputManagerPrivate::get(m_inputManager)->updateHandtracking();
961 enum : size_t { DisplayPeriod = 0, DisplayDelta };
962 qint64 stepSizes[2] {0, 0};
963 auto &[displayPeriodMS, displayDeltaMS] = stepSizes;
964 displayPeriodMS = qint64(cp_time_to_cf_time_interval(optimalInputTime) * 1000.0);
965 displayDeltaMS = ((qint64(cp_time_to_cf_time_interval(cp_frame_timing_get_optimal_input_time(actualTiming)) * 1000.0)) - m_previousTime);
966 const size_t selector = ((m_previousTime == 0) || (displayDeltaMS > displayPeriodMS)) ? DisplayPeriod : DisplayDelta;
967 m_nextStepSize = stepSizes[selector];
968 m_previousTime = displayPeriodMS;
970 if (!multiviewRenderingEnabled) {
971 animationDriver->setStep(m_nextStepSize);
972 animationDriver->advance();
975 QRhi *rhi = renderControl->rhi();
977 const auto viewCount = cp_drawable_get_view_count(drawable);
978 const auto textureCount = cp_drawable_get_texture_count(drawable);
979 const auto renderCalls = textureCount;
982 Q_ASSERT(!foveationEnabled || rhi->isFeatureSupported(QRhi::VariableRateShadingMap));
984 if (foveationEnabled) {
985 const size_t rrmapcount = cp_drawable_get_rasterization_rate_map_count(drawable);
986 const bool validMapCount = (rrmapcount == 1 || rrmapcount == 2);
987 QSSG_GUARD_X(validMapCount,
"Invalid rate map count!");
988 foveationEnabled = validMapCount;
990 if (foveationEnabled) {
991 for (size_t i = 0; i < rrmapcount; ++i) {
993 m_srm[i] = rhi->newShadingRateMap();
994 id<MTLRasterizationRateMap> rrm = cp_drawable_get_rasterization_rate_map(drawable, i);
995 const bool wasCreated = m_srm[i]->createFrom({ quint64(rrm) });
996 QSSG_GUARD_X(wasCreated,
"Failed to create shading rate map!");
997 foveationEnabled = (foveationEnabled && wasCreated);
1010 for (size_t i = 0, end = renderCalls; i != end ; ++i) {
1012 id<MTLTexture> colorMetalTexture = cp_drawable_get_color_texture(drawable, i);
1013 auto textureSize = QSize([colorMetalTexture width], [colorMetalTexture height]);
1015 QQuickRenderTarget renderTarget;
1017 if (multiviewRenderingEnabled)
1018 renderTarget = QQuickRenderTarget::fromMetalTexture(
static_cast<MTLTexture*>(colorMetalTexture), [colorMetalTexture pixelFormat], [colorMetalTexture pixelFormat], textureSize, 1 , viewCount, {});
1020 renderTarget = QQuickRenderTarget::fromMetalTexture(
static_cast<MTLTexture*>(colorMetalTexture), [colorMetalTexture pixelFormat], textureSize);
1022 auto depthMetalTexture = cp_drawable_get_depth_texture(drawable, i);
1023 auto depthTextureSize = QSize([depthMetalTexture width], [depthMetalTexture height]);
1024 MTLPixelFormat depthTextureFormat = [depthMetalTexture pixelFormat];
1025 static const auto convertFormat = [](MTLPixelFormat format) -> QRhiTexture::Format {
1027 case MTLPixelFormatDepth16Unorm:
1028 return QRhiTexture::D16;
1029 case MTLPixelFormatDepth32Float:
1030 return QRhiTexture::D32F;
1032 qWarning(
"Unsupported depth texture format");
1033 return QRhiTexture::UnknownFormat;
1036 auto depthFormat = convertFormat(depthTextureFormat);
1037 if (depthFormat != QRhiTexture::UnknownFormat) {
1038 if (m_rhiDepthTexture && (m_rhiDepthTexture->format() != depthFormat || m_rhiDepthTexture->pixelSize() != depthTextureSize)) {
1039 delete m_rhiDepthTexture;
1040 m_rhiDepthTexture =
nullptr;
1043 if (!m_rhiDepthTexture) {
1044 if (multiviewRenderingEnabled)
1045 m_rhiDepthTexture = rhi->newTextureArray(depthFormat, viewCount, depthTextureSize, 1, QRhiTexture::RenderTarget);
1047 m_rhiDepthTexture = rhi->newTexture(depthFormat, depthTextureSize, 1, QRhiTexture::RenderTarget);
1051 m_rhiDepthTexture->createFrom({ quint64(
static_cast<MTLTexture*>(depthMetalTexture)), 0});
1052 renderTarget.setDepthTexture(m_rhiDepthTexture);
1055 window->setRenderTarget(renderTarget);
1060 QSize renderSize = textureSize;
1061 if (foveationEnabled) {
1062 cp_view_t view = cp_drawable_get_view(drawable, i);
1063 cp_view_texture_map_t texture_map = cp_view_get_view_texture_map(view);
1064 auto vp = cp_view_texture_map_get_viewport(texture_map);
1065 renderSize = QSize(vp.width, vp.height);
1068 window->setGeometry(0,
1071 renderSize.height());
1072 window->contentItem()->setSize(renderSize);
1077 xrViewport->setSize(renderSize);
1080 if (QSSG_GUARD(xrOrigin)) {
1081 if (multiviewRenderingEnabled)
1082 updateCameraMultiview(xrViewport, headTransform, drawable, xrOrigin);
1084 updateCamera(xrViewport, headTransform, drawable, xrOrigin, i);
1090 if (multiviewRenderingEnabled) {
1092 renderControl->beginFrame();
1094 m_syncDone = renderControl->sync();
1096 if (Q_UNLIKELY(!m_syncDone))
1099 if (foveationEnabled)
1100 setupShadingRateMap(window, m_srm[i]);
1103 waitCondition.wakeOne();
1107 renderControl->render();
1109 renderControl->endFrame();
1111 renderControl->polishItems();
1112 renderControl->beginFrame();
1113 renderControl->sync();
1114 if (foveationEnabled)
1115 setupShadingRateMap(window, m_srm[i]);
1116 renderControl->render();
1117 renderControl->endFrame();
1120#if TARGET_OS_SIMULATOR == 1
1124 QRhiRenderTarget *rt = QQuickWindowPrivate::get(window)->activeCustomRhiRenderTarget();
1125 if (rt->resourceType() == QRhiResource::TextureRenderTarget &&
static_cast<QRhiTextureRenderTarget *>(rt)->description().colorAttachmentAt(0)->texture())
1126 emit q->frameReady();
1130 id<MTLCommandBuffer> commandBuffer = [
static_cast<
const QRhiMetalNativeHandles*>(renderControl->rhi()->nativeHandles())->cmdQueue commandBuffer];
1132 cp_drawable_encode_present(drawable, commandBuffer);
1133 [commandBuffer commit];
1135 cp_frame_end_submission(frame);
1142#include "qquick3dxrmanager_visionos.moc"
void arStateChanged(QQuick3DXrManagerPrivate::ArTrackingState)
bool waitForSyncToComplete()
void configure(cp_layer_renderer_capabilities_t capabilities, cp_layer_renderer_configuration_t configuration) const override
static constexpr QEvent::Type asQEvent(CompositorLayer::Event event)
friend bool QQuick3DXrManagerPrivate::renderFrameImpl(QMutexLocker< QMutex > &locker, QWaitCondition &waitCondition)
void getDefaultDepthRange(float &near, float &far) const
static Q_INVOKABLE void destroy(QQuick3DXrManagerPrivate *mngr, QQuickWindow *window, CompositorLayer *compositorLayer)
bool isMultiviewEnabled() const
void layerRendererChanged()
static bool supportsLayoutType(cp_layer_renderer_capabilities_t capabilities, cp_layer_renderer_layout layout)
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
void renderStateChanged(QQuick3DXrManagerPrivate::RenderState)
cp_layer_renderer_t layerRenderer() const
bool isMultiviewSupported() const
bool isFoveationEnabled() const
void render(cp_layer_renderer_t renderer) override
void handleSpatialEvents(const QJsonObject &events) override
void init(QQuick3DXrManagerPrivate *xrManager)
bool isFoveationSupported() const
bool isInitialized() const
QQuick3DXrManagerPrivate(QQuick3DXrManager &manager)
void setupWindow(QQuickWindow *window)
QVersionNumber runtimeVersion() const
QtQuick3DXr::ReferenceSpace getReferenceSpace() const
void setReferenceSpace(QtQuick3DXr::ReferenceSpace newReferenceSpace)
~QQuick3DXrManagerPrivate()
bool supportsPassthrough() const
bool setupGraphics(QQuickWindow *window)
void setMultiViewRenderingEnabled(bool enable)
bool isMultiViewRenderingEnabled() const
void setDepthSubmissionEnabled(bool enable)
void processSpatialEvents(const QJsonObject &events)
QString errorString() const
void setSamples(int samples)
void getDefaultClipDistances(float &nearClip, float &farClip) const
bool isGraphicsInitialized() const
bool setPassthroughEnabled(bool enable)
QString runtimeName() const
static bool isMultiviewRenderingDisabled()
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
static const char s_renderThreadName[]
static bool qssgDisableFoveation()
QPointer< CompositorLayer > instance