From 832043fc7fb8157092449dba832e0ebec9081af3 Mon Sep 17 00:00:00 2001 From: jp9000 Date: Mon, 25 Jan 2016 17:09:59 -0800 Subject: [PATCH] UI: Disable OSX V-Sync when program is open OSX has an annoying feature called "BeamSync", which on later versions of OSX is always on. For whatever reason, Apple devs decided to force this feature to always be on, so applications must always render with v-sync regardless of what they set their swap interval to. This issue would cause syncing to the vertical refresh for each additional active display, and wouldn't allow rendering above the current refresh rate. This caused major rendering stalls and prevented video frame timing from being accurate. This fixes the issue by using an undocumented set of functions to disable BeamSync. Note that because this is an undocumented method of working around the issue, its existence cannot be guaranteed. If the functions no longer exist for whatever reason, it will safely do nothing. --- obs/data/locale/en-US.ini | 2 ++ obs/forms/OBSBasicSettings.ui | 14 ++++++++++++ obs/obs-app.cpp | 20 ++++++++++++++++ obs/platform-osx.mm | 31 +++++++++++++++++++++++++ obs/platform.hpp | 4 ++++ obs/window-basic-settings.cpp | 43 +++++++++++++++++++++++++++++++++++ obs/window-basic-settings.hpp | 2 ++ 7 files changed, 116 insertions(+) diff --git a/obs/data/locale/en-US.ini b/obs/data/locale/en-US.ini index 3253831bc..67793c074 100644 --- a/obs/data/locale/en-US.ini +++ b/obs/data/locale/en-US.ini @@ -43,6 +43,8 @@ Untitled="Untitled" New="New" Duplicate="Duplicate" Enable="Enable" +DisableOSXVSync="Disable OSX V-Sync" +ResetOSXVSyncOnExit="Reset OSX V-Sync on Exit" HighResourceUsage="Encoding overloaded! Consider turning down video settings or using a faster encoding preset." # title bar strings diff --git a/obs/forms/OBSBasicSettings.ui b/obs/forms/OBSBasicSettings.ui index 267722e0c..ee47eee90 100644 --- a/obs/forms/OBSBasicSettings.ui +++ b/obs/forms/OBSBasicSettings.ui @@ -2824,6 +2824,20 @@ + + + + DisableOSXVSync + + + + + + + ResetOSXVSyncOnExit + + + diff --git a/obs/obs-app.cpp b/obs/obs-app.cpp index d273c128d..d0ab9902b 100644 --- a/obs/obs-app.cpp +++ b/obs/obs-app.cpp @@ -333,6 +333,12 @@ bool OBSApp::InitGlobalConfigDefaults() config_set_default_bool(globalConfig, "BasicWindow", "PreviewEnabled", true); + +#ifdef __APPLE__ + config_set_default_bool(globalConfig, "Video", "DisableOSXVSync", true); + config_set_default_bool(globalConfig, "Video", "ResetOSXVSyncOnExit", + true); +#endif return true; } @@ -530,6 +536,15 @@ OBSApp::OBSApp(int &argc, char **argv, profiler_name_store_t *store) OBSApp::~OBSApp() { +#ifdef __APPLE__ + bool vsyncDiabled = config_get_bool(globalConfig, "Video", + "DisableOSXVSync"); + bool resetVSync = config_get_bool(globalConfig, "Video", + "ResetOSXVSyncOnExit"); + if (vsyncDiabled && resetVSync) + EnableOSXVSync(true); +#endif + os_inhibit_sleep_set_active(sleepInhibitor, false); os_inhibit_sleep_destroy(sleepInhibitor); } @@ -639,6 +654,11 @@ void OBSApp::AppInit() config_set_default_string(globalConfig, "Basic", "SceneCollectionFile", Str("Untitled")); +#ifdef __APPLE__ + if (config_get_bool(globalConfig, "Video", "DisableOSXVSync")) + EnableOSXVSync(false); +#endif + move_basic_to_profiles(); move_basic_to_scene_collections(); diff --git a/obs/platform-osx.mm b/obs/platform-osx.mm index 8f68ea43f..ec02bbec4 100644 --- a/obs/platform-osx.mm +++ b/obs/platform-osx.mm @@ -16,6 +16,7 @@ ******************************************************************************/ #include +#include #include #include #include "platform.hpp" @@ -148,3 +149,33 @@ void SetAlwaysOnTop(QMainWindow *window, bool enable) window->setWindowFlags(flags); window->show(); } + +typedef void (*set_int_t)(int); + +void EnableOSXVSync(bool enable) +{ + static bool initialized = false; + static bool valid = false; + static set_int_t set_debug_options = nullptr; + static set_int_t deferred_updates = nullptr; + + if (!initialized) { + void *quartzCore = dlopen("/System/Library/Frameworks/" + "QuartzCore.framework/QuartzCore", RTLD_LAZY); + if (quartzCore) { + set_debug_options = (set_int_t)dlsym(quartzCore, + "CGSSetDebugOptions"); + deferred_updates = (set_int_t)dlsym(quartzCore, + "CGSDeferredUpdates"); + + valid = set_debug_options && deferred_updates; + } + + initialized = true; + } + + if (valid) { + set_debug_options(enable ? 0 : 0x08000000); + deferred_updates(enable ? 1 : 0); + } +} diff --git a/obs/platform.hpp b/obs/platform.hpp index 5f1658910..de9d1c660 100644 --- a/obs/platform.hpp +++ b/obs/platform.hpp @@ -52,3 +52,7 @@ void SetAlwaysOnTop(QMainWindow *window, bool enable); uint32_t GetWindowsVersion(); void SetAeroEnabled(bool enable); #endif + +#ifdef __APPLE__ +void EnableOSXVSync(bool enable); +#endif diff --git a/obs/window-basic-settings.cpp b/obs/window-basic-settings.cpp index aef988534..3f89611b1 100644 --- a/obs/window-basic-settings.cpp +++ b/obs/window-basic-settings.cpp @@ -346,6 +346,8 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) HookWidget(ui->colorFormat, COMBO_CHANGED, ADV_CHANGED); HookWidget(ui->colorSpace, COMBO_CHANGED, ADV_CHANGED); HookWidget(ui->colorRange, COMBO_CHANGED, ADV_CHANGED); + HookWidget(ui->disableOSXVSync, CHECK_CHANGED, ADV_CHANGED); + HookWidget(ui->resetOSXVSync, CHECK_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelayEnable, CHECK_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelaySec, SCROLL_CHANGED, ADV_CHANGED); HookWidget(ui->streamDelayPreserve, CHECK_CHANGED, ADV_CHANGED); @@ -378,6 +380,13 @@ OBSBasicSettings::OBSBasicSettings(QWidget *parent) ui->adapter = nullptr; #endif +#ifndef __APPLE__ + delete ui->disableOSXVSync; + delete ui->resetOSXVSync; + ui->disableOSXVSync = nullptr; + ui->resetOSXVSync = nullptr; +#endif + connect(ui->streamDelaySec, SIGNAL(valueChanged(int)), this, SLOT(UpdateStreamDelayEstimate())); connect(ui->outputMode, SIGNAL(currentIndexChanged(int)), @@ -1676,6 +1685,16 @@ void OBSBasicSettings::LoadAdvancedSettings() ui->advancedVideoContainer->setEnabled(false); } +#ifdef __APPLE__ + bool disableOSXVSync = config_get_bool(App()->GlobalConfig(), + "Video", "DisableOSXVSync"); + bool resetOSXVSync = config_get_bool(App()->GlobalConfig(), + "Video", "ResetOSXVSyncOnExit"); + ui->disableOSXVSync->setChecked(disableOSXVSync); + ui->resetOSXVSync->setChecked(resetOSXVSync); + ui->resetOSXVSync->setEnabled(disableOSXVSync); +#endif + loading = false; } @@ -2074,6 +2093,20 @@ void OBSBasicSettings::SaveAdvancedSettings() config_set_string(App()->GlobalConfig(), "Video", "Renderer", QT_TO_UTF8(ui->renderer->currentText())); #endif + +#ifdef __APPLE__ + if (WidgetChanged(ui->disableOSXVSync)) { + bool disable = ui->disableOSXVSync->isChecked(); + config_set_bool(App()->GlobalConfig(), + "Video", "DisableOSXVSync", disable); + EnableOSXVSync(!disable); + } + if (WidgetChanged(ui->resetOSXVSync)) + config_set_bool(App()->GlobalConfig(), + "Video", "ResetOSXVSyncOnExit", + ui->resetOSXVSync->isChecked()); +#endif + SaveSpinBox(ui->audioBufferingTime, "Audio", "BufferingTime"); SaveCombo(ui->colorFormat, "Video", "ColorFormat"); SaveCombo(ui->colorSpace, "Video", "ColorSpace"); @@ -2992,3 +3025,13 @@ void OBSBasicSettings::SimpleRecordingQualityLosslessWarning(int idx) lastSimpleRecQualityIdx = idx; } + +void OBSBasicSettings::on_disableOSXVSync_clicked() +{ +#ifdef __APPLE__ + if (!loading) { + bool disable = ui->disableOSXVSync->isChecked(); + ui->resetOSXVSync->setEnabled(disable); + } +#endif +} diff --git a/obs/window-basic-settings.hpp b/obs/window-basic-settings.hpp index 8a592897e..ded66eedd 100644 --- a/obs/window-basic-settings.hpp +++ b/obs/window-basic-settings.hpp @@ -256,6 +256,8 @@ private slots: void on_outputResolution_editTextChanged(const QString &text); void on_baseResolution_editTextChanged(const QString &text); + void on_disableOSXVSync_clicked(); + void GeneralChanged(); void AudioChanged(); void AudioChangedRestart();