mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2026-02-16 02:30:52 +00:00
Move heavy SystemProperties loads to an opt-in model
This avoids heavyweight operations when we're not actually running config checks.
This commit is contained in:
@@ -98,51 +98,16 @@ SystemProperties::SystemProperties()
|
|||||||
hasDiscordIntegration = false;
|
hasDiscordIntegration = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unmappedGamepads = SdlInputHandler::getUnmappedGamepads();
|
|
||||||
|
|
||||||
// These will be queried asynchronously to avoid blocking the UI
|
// These will be queried asynchronously to avoid blocking the UI
|
||||||
hasHardwareAcceleration = true;
|
hasHardwareAcceleration = true;
|
||||||
rendererAlwaysFullScreen = false;
|
rendererAlwaysFullScreen = false;
|
||||||
supportsHdr = true;
|
supportsHdr = true;
|
||||||
maximumResolution = QSize(0, 0);
|
maximumResolution = QSize(0, 0);
|
||||||
|
|
||||||
// We initialize the video subsystem and test window on the main thread
|
|
||||||
// because some platforms (macOS) do not support window creation on
|
|
||||||
// non-main threads.
|
|
||||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update display related attributes (max FPS, native resolution, etc).
|
|
||||||
refreshDisplays();
|
|
||||||
|
|
||||||
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720,
|
|
||||||
SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags());
|
|
||||||
if (!testWindow) {
|
|
||||||
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to create test window with platform flags: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
|
|
||||||
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
|
|
||||||
if (!testWindow) {
|
|
||||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
|
||||||
"Failed to create window for hardware decode test: %s",
|
|
||||||
SDL_GetError());
|
|
||||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
systemPropertyQueryThread = new SystemPropertyQueryThread(this);
|
|
||||||
systemPropertyQueryThread->start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SystemProperties::~SystemProperties()
|
SystemProperties::~SystemProperties()
|
||||||
{
|
{
|
||||||
systemPropertyQueryThread->wait();
|
waitForAsyncLoad();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemProperties::updateDecoderProperties(bool hasHardwareAcceleration, bool rendererAlwaysFullScreen, QSize maximumResolution, bool supportsHdr)
|
void SystemProperties::updateDecoderProperties(bool hasHardwareAcceleration, bool rendererAlwaysFullScreen, QSize maximumResolution, bool supportsHdr)
|
||||||
@@ -177,7 +142,6 @@ void SystemProperties::updateDecoderProperties(bool hasHardwareAcceleration, boo
|
|||||||
QRect SystemProperties::getNativeResolution(int displayIndex)
|
QRect SystemProperties::getNativeResolution(int displayIndex)
|
||||||
{
|
{
|
||||||
// Returns default constructed QRect if out of bounds
|
// Returns default constructed QRect if out of bounds
|
||||||
systemPropertyQueryThread->wait();
|
|
||||||
Q_ASSERT(!monitorNativeResolutions.isEmpty());
|
Q_ASSERT(!monitorNativeResolutions.isEmpty());
|
||||||
return monitorNativeResolutions.value(displayIndex);
|
return monitorNativeResolutions.value(displayIndex);
|
||||||
}
|
}
|
||||||
@@ -185,7 +149,6 @@ QRect SystemProperties::getNativeResolution(int displayIndex)
|
|||||||
QRect SystemProperties::getSafeAreaResolution(int displayIndex)
|
QRect SystemProperties::getSafeAreaResolution(int displayIndex)
|
||||||
{
|
{
|
||||||
// Returns default constructed QRect if out of bounds
|
// Returns default constructed QRect if out of bounds
|
||||||
systemPropertyQueryThread->wait();
|
|
||||||
Q_ASSERT(!monitorSafeAreaResolutions.isEmpty());
|
Q_ASSERT(!monitorSafeAreaResolutions.isEmpty());
|
||||||
return monitorSafeAreaResolutions.value(displayIndex);
|
return monitorSafeAreaResolutions.value(displayIndex);
|
||||||
}
|
}
|
||||||
@@ -193,11 +156,66 @@ QRect SystemProperties::getSafeAreaResolution(int displayIndex)
|
|||||||
int SystemProperties::getRefreshRate(int displayIndex)
|
int SystemProperties::getRefreshRate(int displayIndex)
|
||||||
{
|
{
|
||||||
// Returns 0 if out of bounds
|
// Returns 0 if out of bounds
|
||||||
systemPropertyQueryThread->wait();
|
|
||||||
Q_ASSERT(!monitorRefreshRates.isEmpty());
|
Q_ASSERT(!monitorRefreshRates.isEmpty());
|
||||||
return monitorRefreshRates.value(displayIndex);
|
return monitorRefreshRates.value(displayIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SystemProperties::startAsyncLoad()
|
||||||
|
{
|
||||||
|
if (systemPropertyQueryThread) {
|
||||||
|
// Already started/completed
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This isn't actually asynchronous (due to the need to synchronize with
|
||||||
|
// SdlGamepadKeyNavigation), but we don't query it in the constructor
|
||||||
|
// because it's expensive.
|
||||||
|
unmappedGamepads = SdlInputHandler::getUnmappedGamepads();
|
||||||
|
if (!unmappedGamepads.isEmpty()) {
|
||||||
|
emit unmappedGamepadsChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We initialize the video subsystem and test window on the main thread
|
||||||
|
// because some platforms (macOS) do not support window creation on
|
||||||
|
// non-main threads.
|
||||||
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update display related attributes (max FPS, native resolution, etc).
|
||||||
|
refreshDisplays();
|
||||||
|
|
||||||
|
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720,
|
||||||
|
SDL_WINDOW_HIDDEN | StreamUtils::getPlatformWindowFlags());
|
||||||
|
if (!testWindow) {
|
||||||
|
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to create test window with platform flags: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
|
||||||
|
testWindow = SDL_CreateWindow("", 0, 0, 1280, 720, SDL_WINDOW_HIDDEN);
|
||||||
|
if (!testWindow) {
|
||||||
|
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||||
|
"Failed to create window for hardware decode test: %s",
|
||||||
|
SDL_GetError());
|
||||||
|
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
systemPropertyQueryThread = new SystemPropertyQueryThread(this);
|
||||||
|
systemPropertyQueryThread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemProperties::waitForAsyncLoad()
|
||||||
|
{
|
||||||
|
if (systemPropertyQueryThread) {
|
||||||
|
systemPropertyQueryThread->wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void SystemProperties::refreshDisplays()
|
void SystemProperties::refreshDisplays()
|
||||||
{
|
{
|
||||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||||
|
|||||||
@@ -26,18 +26,22 @@ public:
|
|||||||
Q_PROPERTY(bool usesMaterial3Theme MEMBER usesMaterial3Theme CONSTANT)
|
Q_PROPERTY(bool usesMaterial3Theme MEMBER usesMaterial3Theme CONSTANT)
|
||||||
Q_PROPERTY(QString versionString MEMBER versionString CONSTANT)
|
Q_PROPERTY(QString versionString MEMBER versionString CONSTANT)
|
||||||
|
|
||||||
// Properties queried asynchronously
|
// Properties queried asynchronously (startAsyncLoad() must be called!)
|
||||||
Q_PROPERTY(bool hasHardwareAcceleration MEMBER hasHardwareAcceleration NOTIFY hasHardwareAccelerationChanged)
|
Q_PROPERTY(bool hasHardwareAcceleration MEMBER hasHardwareAcceleration NOTIFY hasHardwareAccelerationChanged)
|
||||||
Q_PROPERTY(bool rendererAlwaysFullScreen MEMBER rendererAlwaysFullScreen NOTIFY rendererAlwaysFullScreenChanged)
|
Q_PROPERTY(bool rendererAlwaysFullScreen MEMBER rendererAlwaysFullScreen NOTIFY rendererAlwaysFullScreenChanged)
|
||||||
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
|
Q_PROPERTY(QString unmappedGamepads MEMBER unmappedGamepads NOTIFY unmappedGamepadsChanged)
|
||||||
Q_PROPERTY(QSize maximumResolution MEMBER maximumResolution NOTIFY maximumResolutionChanged)
|
Q_PROPERTY(QSize maximumResolution MEMBER maximumResolution NOTIFY maximumResolutionChanged)
|
||||||
Q_PROPERTY(bool supportsHdr MEMBER supportsHdr NOTIFY supportsHdrChanged)
|
Q_PROPERTY(bool supportsHdr MEMBER supportsHdr NOTIFY supportsHdrChanged)
|
||||||
|
|
||||||
Q_INVOKABLE void refreshDisplays();
|
// Either startAsyncLoad()+waitForAsyncLoad() or refreshDisplays() must be invoked first
|
||||||
Q_INVOKABLE QRect getNativeResolution(int displayIndex);
|
Q_INVOKABLE QRect getNativeResolution(int displayIndex);
|
||||||
Q_INVOKABLE QRect getSafeAreaResolution(int displayIndex);
|
Q_INVOKABLE QRect getSafeAreaResolution(int displayIndex);
|
||||||
Q_INVOKABLE int getRefreshRate(int displayIndex);
|
Q_INVOKABLE int getRefreshRate(int displayIndex);
|
||||||
|
|
||||||
|
Q_INVOKABLE void startAsyncLoad();
|
||||||
|
Q_INVOKABLE void waitForAsyncLoad();
|
||||||
|
Q_INVOKABLE void refreshDisplays();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void unmappedGamepadsChanged();
|
void unmappedGamepadsChanged();
|
||||||
void hasHardwareAccelerationChanged();
|
void hasHardwareAccelerationChanged();
|
||||||
@@ -49,8 +53,8 @@ private slots:
|
|||||||
void updateDecoderProperties(bool hasHardwareAcceleration, bool rendererAlwaysFullScreen, QSize maximumResolution, bool supportsHdr);
|
void updateDecoderProperties(bool hasHardwareAcceleration, bool rendererAlwaysFullScreen, QSize maximumResolution, bool supportsHdr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QThread* systemPropertyQueryThread;
|
QThread* systemPropertyQueryThread = nullptr;
|
||||||
SDL_Window* testWindow;
|
SDL_Window* testWindow = nullptr;
|
||||||
|
|
||||||
// Properties set by the constructor
|
// Properties set by the constructor
|
||||||
bool isRunningWayland;
|
bool isRunningWayland;
|
||||||
@@ -60,15 +64,15 @@ private:
|
|||||||
bool hasDesktopEnvironment;
|
bool hasDesktopEnvironment;
|
||||||
bool hasBrowser;
|
bool hasBrowser;
|
||||||
bool hasDiscordIntegration;
|
bool hasDiscordIntegration;
|
||||||
QString unmappedGamepads;
|
|
||||||
QString versionString;
|
QString versionString;
|
||||||
bool usesMaterial3Theme;
|
bool usesMaterial3Theme;
|
||||||
|
|
||||||
// Properties set by updateDecoderProperties()
|
// Properties only set if startAsyncLoad() is called
|
||||||
bool hasHardwareAcceleration;
|
bool hasHardwareAcceleration;
|
||||||
bool rendererAlwaysFullScreen;
|
bool rendererAlwaysFullScreen;
|
||||||
QSize maximumResolution;
|
QSize maximumResolution;
|
||||||
bool supportsHdr;
|
bool supportsHdr;
|
||||||
|
QString unmappedGamepads;
|
||||||
|
|
||||||
// Properties set by refreshDisplays()
|
// Properties set by refreshDisplays()
|
||||||
QList<QRect> monitorNativeResolutions;
|
QList<QRect> monitorNativeResolutions;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import QtQuick.Window 2.2
|
|||||||
|
|
||||||
import SdlGamepadKeyNavigation 1.0
|
import SdlGamepadKeyNavigation 1.0
|
||||||
import Session 1.0
|
import Session 1.0
|
||||||
|
import SystemProperties 1.0
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property Session session
|
property Session session
|
||||||
@@ -120,6 +121,10 @@ Item {
|
|||||||
session.sessionFinished.connect(sessionFinished)
|
session.sessionFinished.connect(sessionFinished)
|
||||||
session.readyForDeletion.connect(sessionReadyForDeletion)
|
session.readyForDeletion.connect(sessionReadyForDeletion)
|
||||||
|
|
||||||
|
// Ensure the SystemProperties async thread is finished,
|
||||||
|
// since it may currently be using the SDL video subsystem
|
||||||
|
SystemProperties.waitForAsyncLoad()
|
||||||
|
|
||||||
// Kick off the stream
|
// Kick off the stream
|
||||||
spinnerTimer.start()
|
spinnerTimer.start()
|
||||||
streamLoader.active = true
|
streamLoader.active = true
|
||||||
|
|||||||
@@ -56,13 +56,10 @@ ApplicationWindow {
|
|||||||
wow64Dialog.open()
|
wow64Dialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SystemProperties.unmappedGamepads) {
|
// Hardware acceleration and unmapped gamepads are checked asynchronously
|
||||||
unmappedGamepadDialog.unmappedGamepads = SystemProperties.unmappedGamepads
|
|
||||||
unmappedGamepadDialog.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hardware acceleration is checked asynchronously
|
|
||||||
SystemProperties.hasHardwareAccelerationChanged.connect(hasHardwareAccelerationChanged)
|
SystemProperties.hasHardwareAccelerationChanged.connect(hasHardwareAccelerationChanged)
|
||||||
|
SystemProperties.unmappedGamepadsChanged.connect(hasUnmappedGamepadsChanged)
|
||||||
|
SystemProperties.startAsyncLoad()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +74,13 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasUnmappedGamepadsChanged() {
|
||||||
|
if (SystemProperties.unmappedGamepads) {
|
||||||
|
unmappedGamepadDialog.unmappedGamepads = SystemProperties.unmappedGamepads
|
||||||
|
unmappedGamepadDialog.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// It would be better to use TextMetrics here, but it always lays out
|
// It would be better to use TextMetrics here, but it always lays out
|
||||||
// the text slightly more compactly than real Text does in ToolTip,
|
// the text slightly more compactly than real Text does in ToolTip,
|
||||||
// causing unexpected line breaks to be inserted
|
// causing unexpected line breaks to be inserted
|
||||||
|
|||||||
Reference in New Issue
Block a user