mirror of
https://github.com/moonlight-stream/moonlight-qt
synced 2024-11-10 13:44:17 +00:00
Only initialize the video subsystem once per launch
This commit is contained in:
parent
c0bf8b9c25
commit
fa4c0e82bd
4 changed files with 67 additions and 106 deletions
|
@ -5,11 +5,6 @@
|
|||
|
||||
SystemProperties::SystemProperties()
|
||||
{
|
||||
hasHardwareAcceleration =
|
||||
Session::isHardwareDecodeAvailable(StreamingPreferences::VDS_AUTO,
|
||||
VIDEO_FORMAT_H264,
|
||||
1920, 1080, 60);
|
||||
|
||||
isRunningWayland = qgetenv("XDG_SESSION_TYPE") == "wayland";
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
|
@ -51,17 +46,11 @@ void SystemProperties::querySdlVideoInfo()
|
|||
{
|
||||
monitorDesktopResolutions.clear();
|
||||
monitorNativeResolutions.clear();
|
||||
hasHardwareAcceleration = false;
|
||||
|
||||
// Never let the maximum drop below 60 FPS
|
||||
maximumStreamingFrameRate = 60;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_DisplayMode bestMode;
|
||||
for (int displayIndex = 0; displayIndex < SDL_GetNumVideoDisplays(); displayIndex++) {
|
||||
SDL_DisplayMode desktopMode;
|
||||
|
@ -97,5 +86,19 @@ void SystemProperties::querySdlVideoInfo()
|
|||
}
|
||||
}
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
SDL_Window* 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());
|
||||
return;
|
||||
}
|
||||
|
||||
hasHardwareAcceleration =
|
||||
Session::isHardwareDecodeAvailable(testWindow,
|
||||
StreamingPreferences::VDS_AUTO,
|
||||
VIDEO_FORMAT_H264,
|
||||
1920, 1080, 60);
|
||||
|
||||
SDL_DestroyWindow(testWindow);
|
||||
}
|
||||
|
|
14
app/main.cpp
14
app/main.cpp
|
@ -308,15 +308,15 @@ int main(int argc, char *argv[])
|
|||
// Register custom metatypes for use in signals
|
||||
qRegisterMetaType<NvApp>("NvApp");
|
||||
|
||||
#ifdef STEAM_LINK
|
||||
// Steam Link requires that we initialize video before creating our
|
||||
// QGuiApplication in order to configure the framebuffer correctly.
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
// It's fine to do on other platforms too, and it can save some time
|
||||
// doing initialization and teardown of the video subsystem after streaming.
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||
"SDL_InitSubSystem(SDL_INIT_VIDEO | SDL_INIT_TIMER) failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
#endif
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
|
@ -438,12 +438,6 @@ int main(int argc, char *argv[])
|
|||
if (engine.rootObjects().isEmpty())
|
||||
return -1;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_TIMER) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_TIMER) failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
|
||||
// Use atexit() to ensure SDL_Quit() is called. This avoids
|
||||
// racing with object destruction where SDL may be used.
|
||||
atexit(SDL_Quit);
|
||||
|
|
|
@ -244,30 +244,13 @@ int Session::drSubmitDecodeUnit(PDECODE_UNIT du)
|
|||
}
|
||||
}
|
||||
|
||||
bool Session::isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelection vds,
|
||||
bool Session::isHardwareDecodeAvailable(SDL_Window* window,
|
||||
StreamingPreferences::VideoDecoderSelection vds,
|
||||
int videoFormat, int width, int height, int frameRate)
|
||||
{
|
||||
IVideoDecoder* decoder;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||
SDL_GetError());
|
||||
return false;
|
||||
}
|
||||
|
||||
SDL_Window* window = SDL_CreateWindow("", 0, 0, width, height, SDL_WINDOW_HIDDEN);
|
||||
if (!window) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to create window for hardware decode test: %s",
|
||||
SDL_GetError());
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, true, false, true, decoder)) {
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -275,35 +258,16 @@ bool Session::isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelect
|
|||
|
||||
delete decoder;
|
||||
|
||||
// This must be called after the decoder is deleted, because
|
||||
// the renderer may want to interact with the window
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Session::getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection vds,
|
||||
int Session::getDecoderCapabilities(SDL_Window* window,
|
||||
StreamingPreferences::VideoDecoderSelection vds,
|
||||
int videoFormat, int width, int height, int frameRate)
|
||||
{
|
||||
IVideoDecoder* decoder;
|
||||
|
||||
// Video must already be initialized to use this function
|
||||
SDL_assert(SDL_WasInit(SDL_INIT_VIDEO));
|
||||
|
||||
SDL_Window* window = SDL_CreateWindow("", 0, 0, width, height, SDL_WINDOW_HIDDEN);
|
||||
if (!window) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"Failed to create window for hardware decode test: %s",
|
||||
SDL_GetError());
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!chooseDecoder(vds, window, videoFormat, width, height, frameRate, true, false, true, decoder)) {
|
||||
SDL_DestroyWindow(window);
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -311,10 +275,6 @@ int Session::getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection
|
|||
|
||||
delete decoder;
|
||||
|
||||
// This must be called after the decoder is deleted, because
|
||||
// the renderer may want to interact with the window
|
||||
SDL_DestroyWindow(window);
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
|
@ -350,8 +310,17 @@ Session::~Session()
|
|||
s_ActiveSessionSemaphore.release();
|
||||
}
|
||||
|
||||
void Session::initialize()
|
||||
bool Session::initialize()
|
||||
{
|
||||
// Create a hidden window to use for decoder initialization tests
|
||||
SDL_Window* 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());
|
||||
return false;
|
||||
}
|
||||
|
||||
qInfo() << "Server GPU:" << m_Computer->gpuModel;
|
||||
qInfo() << "Server GFE version:" << m_Computer->gfeVersion;
|
||||
|
||||
|
@ -404,7 +373,8 @@ void Session::initialize()
|
|||
case StreamingPreferences::VCC_AUTO:
|
||||
// TODO: Determine if HEVC is better depending on the decoder
|
||||
m_StreamConfig.supportsHevc =
|
||||
isHardwareDecodeAvailable(m_Preferences->videoDecoderSelection,
|
||||
isHardwareDecodeAvailable(testWindow,
|
||||
m_Preferences->videoDecoderSelection,
|
||||
VIDEO_FORMAT_H265,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
|
@ -441,6 +411,15 @@ void Session::initialize()
|
|||
break;
|
||||
}
|
||||
|
||||
// Add the capability flags from the chosen decoder/renderer
|
||||
// Requires m_StreamConfig.supportsHevc to be initialized
|
||||
m_VideoCallbacks.capabilities |= getDecoderCapabilities(testWindow,
|
||||
m_Preferences->videoDecoderSelection,
|
||||
m_StreamConfig.supportsHevc ? VIDEO_FORMAT_H265 : VIDEO_FORMAT_H264,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
m_StreamConfig.fps);
|
||||
|
||||
switch (m_Preferences->windowMode)
|
||||
{
|
||||
case StreamingPreferences::WM_FULLSCREEN_DESKTOP:
|
||||
|
@ -451,6 +430,14 @@ void Session::initialize()
|
|||
m_FullScreenFlag = SDL_WINDOW_FULLSCREEN;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for validation errors/warnings and emit
|
||||
// signals for them, if appropriate
|
||||
bool ret = validateLaunch(testWindow);
|
||||
|
||||
SDL_DestroyWindow(testWindow);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Session::emitLaunchWarning(QString text)
|
||||
|
@ -469,7 +456,7 @@ void Session::emitLaunchWarning(QString text)
|
|||
}
|
||||
}
|
||||
|
||||
bool Session::validateLaunch()
|
||||
bool Session::validateLaunch(SDL_Window* testWindow)
|
||||
{
|
||||
QStringList warningList;
|
||||
|
||||
|
@ -489,7 +476,8 @@ bool Session::validateLaunch()
|
|||
bool hevcForced = m_Preferences->videoCodecConfig == StreamingPreferences::VCC_FORCE_HEVC ||
|
||||
m_Preferences->videoCodecConfig == StreamingPreferences::VCC_FORCE_HEVC_HDR;
|
||||
|
||||
if (!isHardwareDecodeAvailable(m_Preferences->videoDecoderSelection,
|
||||
if (!isHardwareDecodeAvailable(testWindow,
|
||||
m_Preferences->videoDecoderSelection,
|
||||
VIDEO_FORMAT_H265,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
|
@ -530,7 +518,8 @@ bool Session::validateLaunch()
|
|||
emitLaunchWarning("Your host PC GPU doesn't support HDR streaming. "
|
||||
"A GeForce GTX 1000-series (Pascal) or later GPU is required for HDR streaming.");
|
||||
}
|
||||
else if (!isHardwareDecodeAvailable(m_Preferences->videoDecoderSelection,
|
||||
else if (!isHardwareDecodeAvailable(testWindow,
|
||||
m_Preferences->videoDecoderSelection,
|
||||
VIDEO_FORMAT_H265_MAIN10,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
|
@ -579,7 +568,8 @@ bool Session::validateLaunch()
|
|||
}
|
||||
|
||||
if (m_Preferences->videoDecoderSelection == StreamingPreferences::VDS_FORCE_HARDWARE &&
|
||||
!isHardwareDecodeAvailable(m_Preferences->videoDecoderSelection,
|
||||
!isHardwareDecodeAvailable(testWindow,
|
||||
m_Preferences->videoDecoderSelection,
|
||||
m_StreamConfig.supportsHevc ? VIDEO_FORMAT_H265 : VIDEO_FORMAT_H264,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
|
@ -816,11 +806,7 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||
// Complete initialization in this deferred context to avoid
|
||||
// calling expensive functions in the constructor (during the
|
||||
// process of loading the StreamSegue).
|
||||
initialize();
|
||||
|
||||
// Check for validation errors/warnings and emit
|
||||
// signals for them, if appropriate
|
||||
if (!validateLaunch()) {
|
||||
if (!initialize()) {
|
||||
emit sessionFinished();
|
||||
return;
|
||||
}
|
||||
|
@ -891,18 +877,6 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||
return;
|
||||
}
|
||||
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_VIDEO));
|
||||
if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_InitSubSystem(SDL_INIT_VIDEO) failed: %s",
|
||||
SDL_GetError());
|
||||
delete m_InputHandler;
|
||||
m_InputHandler = nullptr;
|
||||
emit displayLaunchError(QString::fromLocal8Bit(SDL_GetError()));
|
||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray hostnameStr = m_Computer->activeAddress.toLatin1();
|
||||
QByteArray siAppVersion = m_Computer->appVersion.toLatin1();
|
||||
|
||||
|
@ -919,14 +893,6 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||
hostInfo.serverInfoGfeVersion = siGfeVersion.data();
|
||||
}
|
||||
|
||||
// Add the capability flags from the chosen decoder/renderer
|
||||
// Requires SDL_INIT_VIDEO already done.
|
||||
m_VideoCallbacks.capabilities |= getDecoderCapabilities(m_Preferences->videoDecoderSelection,
|
||||
m_StreamConfig.supportsHevc ? VIDEO_FORMAT_H265 : VIDEO_FORMAT_H264,
|
||||
m_StreamConfig.width,
|
||||
m_StreamConfig.height,
|
||||
m_StreamConfig.fps);
|
||||
|
||||
int err = LiStartConnection(&hostInfo, &m_StreamConfig, &k_ConnCallbacks,
|
||||
&m_VideoCallbacks,
|
||||
m_AudioDisabled ? nullptr : &k_AudioCallbacks,
|
||||
|
@ -936,7 +902,6 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||
// listener.
|
||||
delete m_InputHandler;
|
||||
m_InputHandler = nullptr;
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||
return;
|
||||
}
|
||||
|
@ -960,7 +925,6 @@ void Session::exec(int displayOriginX, int displayOriginY)
|
|||
SDL_GetError());
|
||||
delete m_InputHandler;
|
||||
m_InputHandler = nullptr;
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
QThreadPool::globalInstance()->start(new DeferredSessionCleanupTask(this));
|
||||
return;
|
||||
}
|
||||
|
@ -1276,8 +1240,6 @@ DispatchDeferredCleanup:
|
|||
if (iconSurface != nullptr) {
|
||||
SDL_FreeSurface(iconSurface);
|
||||
}
|
||||
SDL_QuitSubSystem(SDL_INIT_VIDEO);
|
||||
SDL_assert(!SDL_WasInit(SDL_INIT_VIDEO));
|
||||
|
||||
// Cleanup can take a while, so dispatch it to a worker thread.
|
||||
// When it is complete, it will release our s_ActiveSessionSemaphore
|
||||
|
|
|
@ -25,7 +25,8 @@ public:
|
|||
Q_INVOKABLE void exec(int displayOriginX, int displayOriginY);
|
||||
|
||||
static
|
||||
bool isHardwareDecodeAvailable(StreamingPreferences::VideoDecoderSelection vds,
|
||||
bool isHardwareDecodeAvailable(SDL_Window* window,
|
||||
StreamingPreferences::VideoDecoderSelection vds,
|
||||
int videoFormat, int width, int height, int frameRate);
|
||||
|
||||
static Session* get()
|
||||
|
@ -54,14 +55,15 @@ signals:
|
|||
void sessionFinished();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
bool initialize();
|
||||
|
||||
bool validateLaunch();
|
||||
bool validateLaunch(SDL_Window* testWindow);
|
||||
|
||||
void emitLaunchWarning(QString text);
|
||||
|
||||
static
|
||||
int getDecoderCapabilities(StreamingPreferences::VideoDecoderSelection vds,
|
||||
int getDecoderCapabilities(SDL_Window* window,
|
||||
StreamingPreferences::VideoDecoderSelection vds,
|
||||
int videoFormat, int width, int height, int frameRate);
|
||||
|
||||
IAudioRenderer* createAudioRenderer();
|
||||
|
|
Loading…
Reference in a new issue