diff --git a/src/overlaycontroller.cpp b/src/overlaycontroller.cpp index 772f71f..8912ab3 100644 --- a/src/overlaycontroller.cpp +++ b/src/overlaycontroller.cpp @@ -313,6 +313,32 @@ OverlayController::OverlayController( bool desktopMode, appSettings()->setValue( "keyboardThree", defaultDiscordMuteBindings ); } appSettings()->endGroup(); + + // Keep the settings for vsyncDisabled here in main overlaycontroller + appSettings()->beginGroup( "applicationSettings" ); + auto value = appSettings()->value( "vsyncDisabled", m_vsyncDisabled ); + if ( value.isValid() && !value.isNull() ) + { + m_vsyncDisabled = value.toBool(); + } + value = appSettings()->value( "customTickRateMs", m_customTickRateMs ); + if ( value.isValid() && !value.isNull() ) + { + // keep sane tickrate (between 1~k_maxCustomTickRate) + if ( value.toInt() < 1 ) + { + m_customTickRateMs = 1; + } + else if ( value.toInt() > k_maxCustomTickRate ) + { + m_customTickRateMs = k_maxCustomTickRate; + } + else + { + m_customTickRateMs = value.toInt(); + } + } + appSettings()->endGroup(); } OverlayController::~OverlayController() @@ -706,35 +732,115 @@ void OverlayController::processInputBindings() processKeyboardBindings(); } +bool OverlayController::vsyncDisabled() const +{ + return m_vsyncDisabled; +} + +void OverlayController::setVsyncDisabled( bool value, bool notify ) +{ + if ( m_vsyncDisabled == value ) + { + return; + } + m_vsyncDisabled = value; + appSettings()->beginGroup( "applicationSettings" ); + appSettings()->setValue( "vsyncDisabled", m_vsyncDisabled ); + appSettings()->endGroup(); + appSettings()->sync(); + if ( notify ) + { + emit vsyncDisabledChanged( m_vsyncDisabled ); + } +} + +int OverlayController::customTickRateMs() const +{ + return m_customTickRateMs; +} + +void OverlayController::setCustomTickRateMs( int value, bool notify ) +{ + if ( m_customTickRateMs == value ) + { + return; + } + // keep m_customTickRateMs sane (between 1~k_maxCustomTickRate) + if ( value < 1 ) + { + m_customTickRateMs = 1; + } + else if ( value > k_maxCustomTickRate ) + { + m_customTickRateMs = k_maxCustomTickRate; + } + else + { + m_customTickRateMs = value; + } + + appSettings()->beginGroup( "applicationSettings" ); + appSettings()->setValue( "customTickRateMs", m_customTickRateMs ); + appSettings()->endGroup(); + appSettings()->sync(); + if ( notify ) + { + emit customTickRateMsChanged( m_customTickRateMs ); + } +} + // vsync implementation: -// (this function triggers every 1ms) +// this function triggers every 1ms +// this function should remain lightweight and only check if it's time to run +// mainEventLoop() or not. void OverlayController::OnTimeoutPumpEvents() { - // get the current frame number from the VRSystem frame counter - vr::VRSystem()->GetTimeSinceLastVsync( nullptr, &m_currentFrame ); - - // Check if we are in the next frame yet - if ( m_currentFrame > m_lastFrame ) + if ( m_vsyncDisabled ) { - // If the frame has advanced since last check, it's time for our main - // event loop. (this function should trigger about every 11ms assuming - // 90fps compositor) - mainEventLoop(); + // check if it's time for a custom tick rate tick + if ( m_customTickRateCounter > m_customTickRateMs ) + { + mainEventLoop(); + m_customTickRateCounter = 0; + } + else + { + m_customTickRateCounter++; + } + } - // wait for the next frame after executing our main event loop once. - m_lastFrame = m_currentFrame; - m_vsyncTooLateCounter = 0; - } - else if ( m_vsyncTooLateCounter >= k_nonVsyncTickRate ) + // vsync is enabled + else { - mainEventLoop(); - // m_lastFrame = m_currentFrame + 1 skips the next vsync frame in case - // it was just about to trigger, to prevent double updates faster than - // 11ms. - m_lastFrame = m_currentFrame + 1; - m_vsyncTooLateCounter = 0; + // get the current frame number from the VRSystem frame counter + vr::VRSystem()->GetTimeSinceLastVsync( nullptr, &m_currentFrame ); + + // Check if we are in the next frame yet + if ( m_currentFrame > m_lastFrame ) + { + // If the frame has advanced since last check, it's time for our + // main event loop. (this function should trigger about every 11ms + // assuming 90fps compositor) + mainEventLoop(); + + // wait for the next frame after executing our main event loop once. + m_lastFrame = m_currentFrame; + m_vsyncTooLateCounter = 0; + } + else if ( m_vsyncTooLateCounter >= k_nonVsyncTickRate ) + { + mainEventLoop(); + // m_lastFrame = m_currentFrame + 1 skips the next vsync frame in + // case it was just about to trigger, to prevent double updates + // faster than 11ms. + m_lastFrame = m_currentFrame + 1; + m_vsyncTooLateCounter = 0; + } + else + { + m_vsyncTooLateCounter++; + } } - m_vsyncTooLateCounter++; } void OverlayController::mainEventLoop() diff --git a/src/overlaycontroller.h b/src/overlaycontroller.h index 1921fd8..d358cc4 100644 --- a/src/overlaycontroller.h +++ b/src/overlaycontroller.h @@ -72,12 +72,17 @@ constexpr int k_utilitiesSettingsUpdateCounter = 19; // k_nonVsyncTickRate determines number of ms we wait to force the next event // loop tick when vsync is too late due to dropped frames. constexpr int k_nonVsyncTickRate = 20; +constexpr int k_maxCustomTickRate = 999; constexpr int k_hmdRotationCounterUpdateRate = 7; class OverlayController : public QObject { Q_OBJECT Q_PROPERTY( bool m_desktopMode READ isDesktopMode ) + Q_PROPERTY( bool vsyncDisabled READ vsyncDisabled WRITE setVsyncDisabled + NOTIFY vsyncDisabledChanged ) + Q_PROPERTY( int customTickRateMs READ customTickRateMs WRITE + setCustomTickRateMs NOTIFY customTickRateMsChanged ) private: vr::VROverlayHandle_t m_ulOverlayHandle = vr::k_ulOverlayHandleInvalid; @@ -99,6 +104,8 @@ private: bool m_desktopMode; bool m_noSound; + bool m_vsyncDisabled = false; + int m_customTickRateMs = 20; QUrl m_runtimePathUrl; @@ -111,6 +118,7 @@ private: uint64_t m_currentFrame = 0; uint64_t m_lastFrame = 0; int m_vsyncTooLateCounter = 0; + int m_customTickRateCounter = 0; input::SteamIVRInput m_actions; @@ -194,6 +202,9 @@ public: vr::VREvent_t* pEvent ); void mainEventLoop(); + bool vsyncDisabled() const; + int customTickRateMs() const; + public slots: void renderOverlay(); void OnRenderRequest(); @@ -207,8 +218,13 @@ public slots: void setAlarm01SoundVolume( float vol ); void cancelAlarm01Sound(); + void setVsyncDisabled( bool value, bool notify = true ); + void setCustomTickRateMs( int value, bool notify = true ); + signals: void keyBoardInputSignal( QString input, unsigned long userValue = 0 ); + void vsyncDisabledChanged( bool value ); + void customTickRateMsChanged( int value ); private: static QSettings* _appSettings; diff --git a/src/res/qml/SettingsPage.qml b/src/res/qml/SettingsPage.qml index 37bceed..cdd11d2 100644 --- a/src/res/qml/SettingsPage.qml +++ b/src/res/qml/SettingsPage.qml @@ -50,16 +50,78 @@ MyStackViewPage { } } + + RowLayout { + Layout.fillWidth: true + + MyToggleButton { + id: vsyncDisabledToggle + text: "Disable App Vsync" + onCheckedChanged: { + OverlayController.setVsyncDisabled(checked, true) + customTickRateText.visible = checked + customTickRateLabel.visible = checked + customTickRateMsLabel.visible = checked + } + } + + MyText { + id: customTickRateLabel + text: "Custom Tick Rate: " + horizontalAlignment: Text.AlignRight + Layout.leftMargin: 20 + Layout.rightMargin: 2 + } + + MyTextField { + id: customTickRateText + text: "20" + keyBoardUID: 1001 + Layout.preferredWidth: 140 + Layout.leftMargin: 10 + Layout.rightMargin: 1 + horizontalAlignment: Text.AlignHCenter + function onInputEvent(input) { + var val = parseInt(input, 10) + if (!isNaN(val)) { + OverlayController.customTickRateMs = val + text = OverlayController.customTickRateMs + } else { + text = OverlayController.customTickRateMs + } + } + } + + MyText { + id: customTickRateMsLabel + text: "ms" + horizontalAlignment: Text.AlignLeft + Layout.leftMargin: 1 + } + + Item { + Layout.fillWidth: true + } + } + Item { Layout.fillHeight: true } + Component.onCompleted: { settingsAutoStartToggle.checked = SettingsTabController.autoStartEnabled forceReviveToggle.checked = SettingsTabController.forceRevivePage + allowExternalEditsToggle.checked = MoveCenterTabController.allowExternalEdits oldStyleMotionToggle.checked = MoveCenterTabController.oldStyleMotion universeCenteredRotationToggle.checked = MoveCenterTabController.universeCenteredRotation + + customTickRateText.text = OverlayController.customTickRateMs + vsyncDisabledToggle.checked = OverlayController.vsyncDisabled + customTickRateText.visible = vsyncDisabledToggle.checked + customTickRateLabel.visible = vsyncDisabledToggle.checked + customTickRateMsLabel.visible = vsyncDisabledToggle.checked } Connections { @@ -84,5 +146,18 @@ MyStackViewPage { universeCenteredRotationToggle.checked = MoveCenterTabController.universeCenteredRotation } } + + Connections { + target: OverlayController + onVsyncDisabledChanged: { + vsyncDisabledToggle.checked = OverlayController.vsyncDisabled + customTickRateText.visible = vsyncDisabledToggle.checked + customTickRateLabel.visible = vsyncDisabledToggle.checked + customTickRateMsLabel.visible = vsyncDisabledToggle.checked + } + onCustomTickRateMsChanged: { + customTickRateText.text = OverlayController.customTickRateMs + } + } } } diff --git a/src/res/qml/audio_page/dialog_boxes/PttNewProfileDialog.qml b/src/res/qml/audio_page/dialog_boxes/PttNewProfileDialog.qml index 162ccdf..c58327a 100644 --- a/src/res/qml/audio_page/dialog_boxes/PttNewProfileDialog.qml +++ b/src/res/qml/audio_page/dialog_boxes/PttNewProfileDialog.qml @@ -19,7 +19,7 @@ MyDialogOkCancelPopup { } MyTextField { id: pttNewProfileName - keyBoardUID: 590 + keyBoardUID: 591 color: "#cccccc" text: "" Layout.fillWidth: true