From e64b15d2a71aaf0a2c90a2873f0ea3b495486161 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 27 Jan 2022 21:49:03 -0600 Subject: [PATCH] Rework how we deal with window re-creation for EGLRenderer Previously we opted to just lie to SDL and tell it that the current GL context is actually GLES 3.0 when it wasn't. This meant that we avoided our window being recreated for GLES usage on Wayland and KMSDRM, but that meant our 10-bit color change didn't apply either. I suspect this hackery is what led EGLRenderer to get stuck in a state where SDL_CreateRenderer() always failed. Now SDL will recreate our window once to configure a compatible GL API for our renderer. If that fails, we'll move on to a different renderer (which may recreate the window again). --- app/streaming/session.cpp | 5 ++ .../video/ffmpeg-renderers/eglvid.cpp | 68 +++++++++++++++---- 2 files changed, 58 insertions(+), 15 deletions(-) diff --git a/app/streaming/session.cpp b/app/streaming/session.cpp index 8f64c2e6..01f632f3 100644 --- a/app/streaming/session.cpp +++ b/app/streaming/session.cpp @@ -1317,6 +1317,11 @@ void Session::execInternal() SDL_Delay(500); #endif + // Request at least 8 bits per color for GL + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + m_Window = SDL_CreateWindow("Moonlight", x, y, diff --git a/app/streaming/video/ffmpeg-renderers/eglvid.cpp b/app/streaming/video/ffmpeg-renderers/eglvid.cpp index 7d2ece50..4cf9a8da 100644 --- a/app/streaming/video/ffmpeg-renderers/eglvid.cpp +++ b/app/streaming/video/ffmpeg-renderers/eglvid.cpp @@ -128,7 +128,15 @@ EGLRenderer::~EGLRenderer() // Reset the global properties back to what they were before SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "0"); - SDL_GL_ResetAttributes(); + + // We avoid restoring GL profile and version on purpose. SDL + // renderers use that internally to determine what GL version + // the window is using. If we reset it, it may not properly + // reset back to desktop GL if we have to fall back to the + // SDL renderer. + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); } bool EGLRenderer::prepareDecoderContext(AVCodecContext*, AVDictionary**) @@ -454,27 +462,29 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params) return false; } - /* - * Create a dummy renderer in order to craft an accelerated SDL Window. - * Request opengl ES 3.0 context, otherwise it will SIGSEGV - * https://gitlab.freedesktop.org/mesa/mesa/issues/1011 - */ + // This hint will ensure we use EGL to retreive our GL context, + // even on X11 where that is not the default. EGL is required + // to avoid a crash in Mesa. + // https://gitlab.freedesktop.org/mesa/mesa/issues/1011 SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1"); - SDL_GL_ResetAttributes(); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + // Change our GL context to use 10-bit colors for 10-bit content if (params->videoFormat == VIDEO_FORMAT_H265_MAIN10) { + // FIXME: We should try to do this only once per window. + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Changing GL context to 10-bit color"); + + // Initialize our GL attributes to defaults (desktop GL). + // This ensures we will always hit the SDL_RecreateWindow() + // path which will ensure our color buffer changes below + // take effect. + SDL_GL_ResetAttributes(); + + // Request 10-bit color for Main10 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 10); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 10); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 10); } - else { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - } int renderIndex; int maxRenderers = SDL_GetNumRenderDrivers(); @@ -500,6 +510,23 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params) return false; } + // SDL_CreateRenderer() can end up having to recreate our window (SDL_RecreateWindow()) + // to ensure it's compatible with the renderer's OpenGL context. If that happens, we + // 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); + } + SDL_SysWMinfo info; SDL_VERSION(&info.version); if (!SDL_GetWindowWMInfo(params->window, &info)) { @@ -547,6 +574,17 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params) return false; } + { + int r, g, b, a; + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &r); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &g); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &b); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &a); + SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, + "Color buffer is: R%dG%dB%dA%d", + r, g, b, a); + } + SDL_GL_GetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, &m_GlesMajorVersion); SDL_GL_GetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, &m_GlesMinorVersion);