From 0aa41a912be626ffb00e23ff14f5b250882f1bc2 Mon Sep 17 00:00:00 2001 From: wheaney <42350981+wheaney@users.noreply.github.com> Date: Fri, 16 Jan 2026 13:11:27 -0800 Subject: [PATCH] Fix issue with double-counting lens position changes with 6DoF --- kwin/src/breezydesktopeffect.cpp | 13 +++++++++++++ kwin/src/breezydesktopeffect.h | 4 ++++ kwin/src/qml/CameraController.qml | 8 +++++++- kwin/src/qml/Displays.qml | 6 +----- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/kwin/src/breezydesktopeffect.cpp b/kwin/src/breezydesktopeffect.cpp index b5ceab0..c1256e8 100644 --- a/kwin/src/breezydesktopeffect.cpp +++ b/kwin/src/breezydesktopeffect.cpp @@ -469,6 +469,10 @@ quint64 BreezyDesktopEffect::poseTimestamp() const { return m_poseTimestamp; } +bool BreezyDesktopEffect::poseHasPosition() const { + return m_poseHasPosition; +} + QList BreezyDesktopEffect::lookAheadConfig() const { return m_lookAheadConfig; } @@ -718,7 +722,16 @@ void BreezyDesktopEffect::updatePose() { << "diagonalFOV:" << m_diagonalFOV; activate(); m_enabled = true; + m_poseHasPosition = false; + auto driverStateOpt = XRDriverIPC::instance().retrieveDriverState(); + if (driverStateOpt) { + QJsonObject driverState = driverStateOpt.value(); + if (driverState.contains(QStringLiteral("connected_device_pose_has_position"))) { + m_poseHasPosition = driverState.value(QStringLiteral("connected_device_pose_has_position")).toBool(); + } + } Q_EMIT enabledStateChanged(); + Q_EMIT poseHasPositionChanged(); activatedAt = currentTimeMs; } diff --git a/kwin/src/breezydesktopeffect.h b/kwin/src/breezydesktopeffect.h index 560dbb0..9be5552 100644 --- a/kwin/src/breezydesktopeffect.h +++ b/kwin/src/breezydesktopeffect.h @@ -25,6 +25,7 @@ namespace KWin Q_PROPERTY(bool zoomOnFocusEnabled READ isZoomOnFocusEnabled WRITE setZoomOnFocusEnabled NOTIFY zoomOnFocusChanged) Q_PROPERTY(int lookingAtScreenIndex READ lookingAtScreenIndex WRITE setLookingAtScreenIndex) Q_PROPERTY(bool poseResetState READ poseResetState NOTIFY poseResetStateChanged) + Q_PROPERTY(bool poseHasPosition READ poseHasPosition NOTIFY poseResetStateChanged) Q_PROPERTY(QList poseOrientations READ poseOrientations) Q_PROPERTY(QVector3D posePosition READ posePosition) Q_PROPERTY(quint32 poseTimeElapsedMs READ poseTimeElapsedMs) @@ -81,6 +82,7 @@ namespace KWin quint32 poseTimeElapsedMs() const; quint64 poseTimestamp() const; bool poseResetState() const; + bool poseHasPosition() const; QList lookAheadConfig() const; qreal lookAheadOverride() const; void setLookAheadOverride(qreal override); @@ -138,6 +140,7 @@ namespace KWin void enabledStateChanged(); void zoomOnFocusChanged(); void poseResetStateChanged(); + void poseHasPositionChanged(); void sbsEnabledChanged(); void smoothFollowEnabledChanged(); void devicePropertiesChanged(); @@ -175,6 +178,7 @@ namespace KWin int m_lookingAtScreenIndex = -1; int m_effectTargetScreenIndex = -1; bool m_poseResetState; + bool m_poseHasPosition = false; QList m_poseOrientations; QVector3D m_posePosition; quint32 m_poseTimeElapsedMs; diff --git a/kwin/src/qml/CameraController.qml b/kwin/src/qml/CameraController.qml index a2820a1..c82971c 100644 --- a/kwin/src/qml/CameraController.qml +++ b/kwin/src/qml/CameraController.qml @@ -62,7 +62,13 @@ Item { effect.lookAheadOverride ) ); - camera.position = position.times(fovDetails.fullScreenDistancePixels).plus(orientations[0].times(Qt.vector3d(0, 0, -fovDetails.lensDistancePixels))); + let lensVector = Qt.vector3d(0, 0, -fovDetails.lensDistancePixels); + + // if we only have 3DoF, account for a bit of positional change based on orientation, + // don't do this for 6DoF to prevent doubling the positional movement due to rotation + if (!effect.poseHasPosition) lensVector = orientations[0].times(lensVector); + + camera.position = position.times(fovDetails.fullScreenDistancePixels).plus(lensVector); sampleCounter += 1; if (sampleCounter === 60) { diff --git a/kwin/src/qml/Displays.qml b/kwin/src/qml/Displays.qml index f488605..db9904f 100644 --- a/kwin/src/qml/Displays.qml +++ b/kwin/src/qml/Displays.qml @@ -64,7 +64,6 @@ QtObject { } function buildFovDetails(screens, viewportWidth, viewportHeight, viewportDiagonalFOV, lensDistanceRatio, defaultDisplayDistance, wrappingChoice, distanceAdjustedSize) { - console.log(`Breezy - Building FOV details with viewport ${viewportWidth}x${viewportHeight}, diagonal FOV ${viewportDiagonalFOV} degrees, lens distance ratio ${lensDistanceRatio}, default display distance ${defaultDisplayDistance}, wrapping choice ${wrappingChoice}, distance adjusted size ${distanceAdjustedSize}`); const aspect = viewportWidth / viewportHeight; const fovLengths = diagonalToCrossFOVs(degreeToRadian(viewportDiagonalFOV), aspect); @@ -101,7 +100,7 @@ QtObject { // distance of a display at the default (most zoomed out) distance from the pivot point const completeScreenDistancePixels = fullScreenDistancePixels * defaultDisplayDistance; - const details = { + return { widthPixels: viewportWidth, distanceAdjustedSize, sizeAdjustedWidthPixels: viewportWidth * distanceAdjustedSize, @@ -115,9 +114,6 @@ QtObject { monitorWrappingScheme, curvedDisplay: effect.curvedDisplay }; - - console.log("Breezy - FOV Details:", details); - return details; } // Utility constant