Use a barrier to ensure we don't flush important window events

This commit is contained in:
Cameron Gutman 2021-01-09 17:51:25 -06:00
parent e6f59062fa
commit 2d62d090df
3 changed files with 47 additions and 6 deletions

View File

@ -22,6 +22,8 @@
#define ICON_SIZE 64
#endif
#define SDL_CODE_FLUSH_WINDOW_EVENT_BARRIER 100
#include <openssl/rand.h>
#include <QtEndian>
@ -378,6 +380,7 @@ Session::Session(NvComputer* computer, NvApp& app, StreamingPreferences *prefere
m_InputHandler(nullptr),
m_InputHandlerLock(0),
m_MouseEmulationRefCount(0),
m_FlushingWindowEvents(false),
m_AsyncConnectionSuccess(false),
m_PortTestResults(0),
m_OpusDecoder(nullptr),
@ -1093,6 +1096,23 @@ bool Session::startConnectionAsync()
return true;
}
void Session::flushWindowEvents()
{
// Pump events to ensure all pending OS events are posted
SDL_PumpEvents();
// Insert a barrier to discard any additional window events.
// We don't use SDL_FlushEvent() here because it could cause
// important events to be lost.
m_FlushingWindowEvents = true;
// This event will cause us to set m_FlushingWindowEvents back to false.
SDL_Event flushEvent = {};
flushEvent.type = SDL_USEREVENT;
flushEvent.user.code = SDL_CODE_FLUSH_WINDOW_EVENT_BARRIER;
SDL_PushEvent(&flushEvent);
}
void Session::exec(int displayOriginX, int displayOriginY)
{
m_DisplayOriginX = displayOriginX;
@ -1313,6 +1333,9 @@ void Session::exec(int displayOriginX, int displayOriginY)
case SDL_CODE_SHOW_CURSOR:
SDL_ShowCursor(SDL_ENABLE);
break;
case SDL_CODE_FLUSH_WINDOW_EVENT_BARRIER:
m_FlushingWindowEvents = false;
break;
default:
SDL_assert(false);
}
@ -1372,6 +1395,11 @@ void Session::exec(int displayOriginX, int displayOriginY)
SDL_SetWindowPosition(m_Window, x, y);
}
if (m_FlushingWindowEvents) {
// Ignore window events for renderer reset if flushing
break;
}
SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION,
"Recreating renderer for window event: %d (%d %d)",
event.window.event,
@ -1387,10 +1415,11 @@ void Session::exec(int displayOriginX, int displayOriginY)
// Destroy the old decoder
delete m_VideoDecoder;
// Flush any other pending window events that could
// send us back here immediately
SDL_PumpEvents();
SDL_FlushEvent(SDL_WINDOWEVENT);
// Insert a barrier to discard any additional window events
// that could cause the renderer to be and recreated again.
// We don't use SDL_FlushEvent() here because it could cause
// important events to be lost.
flushWindowEvents();
// Update the window display mode based on our current monitor
currentDisplayIndex = SDL_GetWindowDisplayIndex(m_Window);

View File

@ -39,6 +39,8 @@ public:
return m_OverlayManager;
}
void flushWindowEvents();
signals:
void stageStarting(QString stage);
@ -150,6 +152,7 @@ private:
SdlInputHandler* m_InputHandler;
SDL_SpinLock m_InputHandlerLock;
int m_MouseEmulationRefCount;
bool m_FlushingWindowEvents;
bool m_AsyncConnectionSuccess;
int m_PortTestResults;

View File

@ -112,8 +112,17 @@ bool SdlRenderer::initialize(PDECODER_PARAMETERS params)
// can get spurious SDL_WINDOWEVENT events that will cause us to (again) recreate our
// renderer. This can lead to an infinite to renderer recreation, so discard all
// SDL_WINDOWEVENT events after SDL_CreateRenderer().
Session* session = Session::get();
if (session != nullptr) {
// If we get here during a session, we need to synchronize with the event loop
// to ensure we don't drop any important events.
session->flushWindowEvents();
}
else {
// If we get here prior to the start of a session, just pump and flush ourselves.
SDL_PumpEvents();
SDL_FlushEvent(SDL_WINDOWEVENT);
}
// Calculate the video region size, scaling to fill the output size while
// preserving the aspect ratio of the video stream.