From ac89379ca69ab14e197feb340dc7a61048bca2de Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 7 Nov 2020 21:41:25 +1000 Subject: [PATCH] GL/ContextEGL: Use pbuffer when surfaceless not supported --- src/common/gl/context_egl.cpp | 43 +++++++++++++++++++++++++++++++++-- src/common/gl/context_egl.h | 3 +++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/common/gl/context_egl.cpp b/src/common/gl/context_egl.cpp index 15d555904..233e4204d 100644 --- a/src/common/gl/context_egl.cpp +++ b/src/common/gl/context_egl.cpp @@ -48,6 +48,15 @@ bool ContextEGL::Initialize(const Version* versions_to_try, size_t num_versions_ } Log_InfoPrintf("EGL Version: %d.%d", egl_major, egl_minor); + const char* extensions = eglQueryString(m_display, EGL_EXTENSIONS); + if (extensions) + { + Log_InfoPrintf("EGL Extensions: %s", extensions); + m_supports_surfaceless = std::strstr(extensions, "EGL_KHR_surfaceless_context") != nullptr; + } + if (!m_supports_surfaceless) + Log_WarningPrint("EGL implementation does not support surfaceless contexts, emulating with pbuffers"); + for (size_t i = 0; i < num_versions_to_try; i++) { if (CreateContextAndSurface(versions_to_try[i], nullptr, true)) @@ -75,7 +84,7 @@ bool ContextEGL::ChangeSurface(const WindowInfo& new_wi) } m_wi = new_wi; - if (m_wi.type != WindowInfo::Type::Surfaceless && !CreateSurface()) + if (!CreateSurface()) return false; if (was_current && !eglMakeCurrent(m_display, m_surface, m_surface, m_context)) @@ -139,6 +148,7 @@ std::unique_ptr ContextEGL::CreateSharedContext(const WindowInfo& wi) { std::unique_ptr context = std::make_unique(wi); context->m_display = m_display; + context->m_supports_surfaceless = m_supports_surfaceless; if (!context->CreateContextAndSurface(m_version, m_context, false)) return nullptr; @@ -153,6 +163,14 @@ EGLNativeWindowType ContextEGL::GetNativeWindow(EGLConfig config) bool ContextEGL::CreateSurface() { + if (m_wi.type == WindowInfo::Type::Surfaceless) + { + if (m_supports_surfaceless) + return true; + else + return CreatePBufferSurface(); + } + EGLNativeWindowType native_window = GetNativeWindow(m_config); m_surface = eglCreateWindowSurface(m_display, m_config, native_window, nullptr); if (!m_surface) @@ -177,6 +195,27 @@ bool ContextEGL::CreateSurface() return true; } +bool ContextEGL::CreatePBufferSurface() +{ + const u32 width = std::max(m_wi.surface_width, 1); + const u32 height = std::max(m_wi.surface_height, 1); + + // TODO: Format + EGLint attrib_list[] = { + EGL_WIDTH, static_cast(width), EGL_HEIGHT, static_cast(height), EGL_NONE, + }; + + m_surface = eglCreatePbufferSurface(m_display, m_config, attrib_list); + if (!m_surface) + { + Log_ErrorPrintf("eglCreatePbufferSurface() failed: %d", eglGetError()); + return false; + } + + Log_DevPrintf("Created %ux%u pbuffer surface", width, height); + return true; +} + bool ContextEGL::CreateContext(const Version& version, EGLContext share_context) { int surface_attribs[16] = { @@ -264,7 +303,7 @@ bool ContextEGL::CreateContextAndSurface(const Version& version, EGLContext shar if (!CreateContext(version, share_context)) return false; - if (m_wi.type != WindowInfo::Type::Surfaceless && !CreateSurface()) + if (!CreateSurface()) { Log_ErrorPrintf("Failed to create surface for context"); eglDestroyContext(m_display, m_context); diff --git a/src/common/gl/context_egl.h b/src/common/gl/context_egl.h index d2a2e2042..ce228980a 100644 --- a/src/common/gl/context_egl.h +++ b/src/common/gl/context_egl.h @@ -30,12 +30,15 @@ protected: bool CreateContext(const Version& version, EGLContext share_context); bool CreateContextAndSurface(const Version& version, EGLContext share_context, bool make_current); bool CreateSurface(); + bool CreatePBufferSurface(); EGLDisplay m_display = EGL_NO_DISPLAY; EGLSurface m_surface = EGL_NO_SURFACE; EGLContext m_context = EGL_NO_CONTEXT; EGLConfig m_config = {}; + + bool m_supports_surfaceless = false; }; } // namespace GL