From fa4c0e82bde20b8d5b652c81842bda11a692538a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sat, 23 Mar 2019 17:46:42 -0700 Subject: [PATCH] Only initialize the video subsystem once per launch --- app/backend/systemproperties.cpp | 29 ++++---- app/main.cpp | 14 ++-- app/streaming/session.cpp | 120 +++++++++++-------------------- app/streaming/session.h | 10 +-- 4 files changed, 67 insertions(+), 106 deletions(-) diff --git a/app/backend/systemproperties.cpp b/app/backend/systemproperties.cpp index 7b3d0f3d..570bfe92 100644 --- a/app/backend/systemproperties.cpp +++ b/app/backend/systemproperties.cpp @@ -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); } diff --git a/app/main.cpp b/app/main.cpp index 12b2a25a..221a5162 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -308,15 +308,15 @@ int main(int argc, char *argv[]) // Register custom metatypes for use in signals qRegisterMetaType("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); diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 4cb021bb..eb2a3b43 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -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 diff --git a/app/streaming/session.h b/app/streaming/session.h index 8369572c..af2490e4 100644 --- a/app/streaming/session.h +++ b/app/streaming/session.h @@ -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();