Use separate thread for streaming on X11 and Wayland

This commit is contained in:
Cameron Gutman
2021-03-07 10:06:12 -06:00
parent d33ccce683
commit 783a57ef89
2 changed files with 73 additions and 11 deletions
+60 -2
View File
@@ -563,12 +563,15 @@ void Session::emitLaunchWarning(QString text)
// to allow it to transition off the screen before continuing. // to allow it to transition off the screen before continuing.
uint32_t start = SDL_GetTicks(); uint32_t start = SDL_GetTicks();
while (!SDL_TICKS_PASSED(SDL_GetTicks(), start + 3500)) { while (!SDL_TICKS_PASSED(SDL_GetTicks(), start + 3500)) {
// Pump the UI loop while we wait
SDL_Delay(5); SDL_Delay(5);
if (!m_ThreadedExec) {
// Pump the UI loop while we wait if we're on the main thread
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
} }
} }
}
bool Session::validateLaunch(SDL_Window* testWindow) bool Session::validateLaunch(SDL_Window* testWindow)
{ {
@@ -1097,11 +1100,58 @@ void Session::flushWindowEvents()
SDL_PushEvent(&flushEvent); SDL_PushEvent(&flushEvent);
} }
class ExecThread : public QThread
{
public:
ExecThread(Session* session) :
QThread(nullptr),
m_Session(session) {}
void run() override
{
m_Session->execInternal();
}
Session* m_Session;
};
void Session::exec(int displayOriginX, int displayOriginY) void Session::exec(int displayOriginX, int displayOriginY)
{ {
m_DisplayOriginX = displayOriginX; m_DisplayOriginX = displayOriginX;
m_DisplayOriginY = displayOriginY; m_DisplayOriginY = displayOriginY;
// Use a separate thread for the streaming session on X11 or Wayland
// to ensure we don't stomp on Qt's GL context. This breaks when using
// the Qt EGLFS backend, so we will restrict this to X11
m_ThreadedExec = WMUtils::isRunningX11() || WMUtils::isRunningWayland();
if (m_ThreadedExec) {
// Run the streaming session on a separate thread for Linux/BSD
ExecThread execThread(this);
execThread.start();
// Until the SDL streaming window is created, we should continue
// to update the Qt UI to allow warning messages to display and
// make sure that the Qt window can hide itself.
while (!execThread.wait(10) && m_Window == nullptr) {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QCoreApplication::sendPostedEvents();
}
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QCoreApplication::sendPostedEvents();
// SDL is in charge now. Wait until the streaming thread exits
// to further update the Qt window.
execThread.wait();
}
else {
// Run the streaming session on the main thread for Windows and macOS
execInternal();
}
}
void Session::execInternal()
{
// Complete initialization in this deferred context to avoid // Complete initialization in this deferred context to avoid
// calling expensive functions in the constructor (during the // calling expensive functions in the constructor (during the
// process of loading the StreamSegue). // process of loading the StreamSegue).
@@ -1125,8 +1175,9 @@ void Session::exec(int displayOriginX, int displayOriginY)
m_StreamConfig.width, m_StreamConfig.width,
m_StreamConfig.height); m_StreamConfig.height);
// Kick off the async connection thread while we sit here and pump the event loop
AsyncConnectionStartThread asyncConnThread(this); AsyncConnectionStartThread asyncConnThread(this);
if (!m_ThreadedExec) {
// Kick off the async connection thread while we sit here and pump the event loop
asyncConnThread.start(); asyncConnThread.start();
while (!asyncConnThread.wait(10)) { while (!asyncConnThread.wait(10)) {
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
@@ -1137,6 +1188,13 @@ void Session::exec(int displayOriginX, int displayOriginY)
// the thread that happened while it was in the final successful QThread::wait(). // the thread that happened while it was in the final successful QThread::wait().
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
QCoreApplication::sendPostedEvents(); QCoreApplication::sendPostedEvents();
}
else {
// We're already in a separate thread so run the connection operations
// synchronously and don't pump the event loop. The main thread is already
// pumping the event loop for us.
asyncConnThread.run();
}
// If the connection failed, clean up and abort the connection. // If the connection failed, clean up and abort the connection.
if (!m_AsyncConnectionSuccess) { if (!m_AsyncConnectionSuccess) {
+4
View File
@@ -17,6 +17,7 @@ class Session : public QObject
friend class SdlInputHandler; friend class SdlInputHandler;
friend class DeferredSessionCleanupTask; friend class DeferredSessionCleanupTask;
friend class AsyncConnectionStartThread; friend class AsyncConnectionStartThread;
friend class ExecThread;
public: public:
explicit Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences = nullptr); explicit Session(NvComputer* computer, NvApp& app, StreamingPreferences *preferences = nullptr);
@@ -57,6 +58,8 @@ signals:
void sessionFinished(int portTestResult); void sessionFinished(int portTestResult);
private: private:
void execInternal();
bool initialize(); bool initialize();
bool startConnectionAsync(); bool startConnectionAsync();
@@ -148,6 +151,7 @@ private:
Uint32 m_FullScreenFlag; Uint32 m_FullScreenFlag;
int m_DisplayOriginX; int m_DisplayOriginX;
int m_DisplayOriginY; int m_DisplayOriginY;
bool m_ThreadedExec;
bool m_PendingWindowedTransition; bool m_PendingWindowedTransition;
bool m_UnexpectedTermination; bool m_UnexpectedTermination;
SdlInputHandler* m_InputHandler; SdlInputHandler* m_InputHandler;