From 3b2c4ca5e5e367e2af60fffdedd1c69794954bbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 2 Oct 2018 14:25:40 +0200 Subject: [PATCH] Platform: make WindowlessEglApplication working with SwiftShader. There's much more to work around / fix, but this is a start. First we need to create the context with a pbuffer, otherwise eglMakeCurrent() crashes deep inside. Second, it doesn't treat EGL_CONTEXT_FLAGS_KHR as a bitfield, so it blows up when encountering a combination of zero flags. In that case we're simply not sending the flags there. This would also blow up when there's more than one flag passed, but there's just one flag for debug context at the moment, so shouldn't be a problem. --- doc/changelog.dox | 5 ++ .../GL/Implementation/driverSpecific.cpp | 13 ++++- .../Platform/WindowlessEglApplication.cpp | 53 ++++++++++++++++++- .../Platform/WindowlessEglApplication.h | 4 ++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index a2f8815d2..30cf493b7 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -270,6 +270,11 @@ See also: - When using SDL 2.0.8 and newer, @ref Platform::Sdl2Application no longer attempts to disable compositing on Linux. See @ref Platform-Sdl2Application-usage-linux for more information. +- New @cpp "swiftshader-no-empty-egl-context-flags" @ce and + @cpp "swiftshader-egl-context-needs-pbuffer" @ce workarounds to make + @ref Platform::WindowlessEglApplication working with + [SwiftShader](https://github.com/google/swiftshader). See + @ref opengl-workarounds for more information. @subsubsection changelog-latest-changes-shaders Shaders library diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 90a38e651..f2e9fafd7 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -110,7 +110,18 @@ namespace { strings when running on Emscripten with -s USE_PTHREADS=1. Working around that by replacing all chars > 127 with spaces. Relevant code: https://github.com/kripken/emscripten/blob/7f89560101843198787530731f40a65288f6f15f/src/fetch-worker.js#L54-L58 */ - "emscripten-pthreads-broken-unicode-shader-sources" + "emscripten-pthreads-broken-unicode-shader-sources", + #endif + + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + /* Empty EGL_CONTEXT_FLAGS_KHR cause SwiftShader 3.3.0.1 to fail + context creation with EGL_BAD_ATTRIBUTE. Not sending the flags then. + Relevant code: https://github.com/google/swiftshader/blob/5fb5e817a20d3e60f29f7338493f922b5ac9d7c4/src/OpenGL/libEGL/libEGL.cpp#L794-L810 */ + "swiftshader-no-empty-egl-context-flags", + + /* SwiftShader 3.3.0.1 crashes deep inside eglMakeCurrent() when using + EGL_NO_SURFACE. Supplying a 32x32 PBuffer to work around that. */ + "swiftshader-egl-context-needs-pbuffer", #endif /* [workarounds] */ }; diff --git a/src/Magnum/Platform/WindowlessEglApplication.cpp b/src/Magnum/Platform/WindowlessEglApplication.cpp index 8c9bfbda7..8a7ae2f6d 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessEglApplication.cpp @@ -33,9 +33,13 @@ #include "Implementation/Egl.h" +#if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) +#include +#endif + namespace Magnum { namespace Platform { -WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, GLContext*) { +WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, GLContext* const magnumContext) { /* Initialize */ _display = eglGetDisplay(EGL_DEFAULT_DISPLAY); if(!eglInitialize(_display, nullptr, nullptr)) { @@ -84,7 +88,10 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G return; } - const EGLint attributes[] = { + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_WEBGL) + const /* Is modified below to work around a SwiftShader limitation */ + #endif + EGLint attributes[] = { #ifdef MAGNUM_TARGET_GLES EGL_CONTEXT_CLIENT_VERSION, #if defined(MAGNUM_TARGET_GLES2) || defined(CORRADE_TARGET_EMSCRIPTEN) @@ -99,6 +106,8 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G #endif #endif #ifndef MAGNUM_TARGET_WEBGL + /* Needs to be last because we're zeroing this out for SwiftShader (see + below) */ EGL_CONTEXT_FLAGS_KHR, EGLint(configuration.flags()), #endif EGL_NONE @@ -107,11 +116,41 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G #ifdef MAGNUM_TARGET_WEBGL static_cast(configuration); #endif + #if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_WEBGL) + static_cast(magnumContext); + #endif + + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + const std::string version = eglQueryString(_display, EGL_VERSION); + + /* SwiftShader 3.3.0.1 blows up on encountering EGL_CONTEXT_FLAGS_KHR with + a zero value, so erase these. It also doesn't handle them as correct + flags, but instead checks for the whole value, so a combination won't + work either: https://github.com/google/swiftshader/blob/5fb5e817a20d3e60f29f7338493f922b5ac9d7c4/src/OpenGL/libEGL/libEGL.cpp#L794-L8104 */ + if(!configuration.flags() && version.find("SwiftShader") != std::string::npos && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("swiftshader-no-empty-egl-context-flags"))) { + auto& contextFlags = attributes[Containers::arraySize(attributes) - 3]; + CORRADE_INTERNAL_ASSERT(contextFlags == EGL_CONTEXT_FLAGS_KHR); + contextFlags = EGL_NONE; + } + #endif if(!(_context = eglCreateContext(_display, config, EGL_NO_CONTEXT, attributes))) { Error() << "Platform::WindowlessEglApplication::tryCreateContext(): cannot create EGL context:" << Implementation::eglErrorString(eglGetError()); return; } + + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + /* SwiftShader 3.3.0.1 needs some pbuffer, otherwise it crashes somewhere + deep inside when making the context current */ + if(version.find("SwiftShader") != std::string::npos && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("swiftshader-egl-context-needs-pbuffer"))) { + EGLint surfaceAttributes[] = { + EGL_WIDTH, 32, + EGL_HEIGHT, 32, + EGL_NONE + }; + _surface = eglCreatePbufferSurface(_display, config, surfaceAttributes); + } + #endif } WindowlessEglContext::WindowlessEglContext(WindowlessEglContext&& other): _display{other._display}, _context{other._context} { @@ -121,6 +160,9 @@ WindowlessEglContext::WindowlessEglContext(WindowlessEglContext&& other): _displ WindowlessEglContext::~WindowlessEglContext() { if(_context) eglDestroyContext(_display, _context); + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + if(_surface) eglDestroySurface(_display, _surface); + #endif if(_display) eglTerminate(_display); } @@ -132,8 +174,15 @@ WindowlessEglContext& WindowlessEglContext::operator=(WindowlessEglContext && ot } bool WindowlessEglContext::makeCurrent() { + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + /* _surface is EGL_NO_SURFACE everywhere except on SwiftShader. See above + for details. */ + if(eglMakeCurrent(_display, _surface, _surface, _context)) + return true; + #else if(eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, _context)) return true; + #endif Error() << "Platform::WindowlessEglApplication::tryCreateContext(): cannot make context current:" << Implementation::eglErrorString(eglGetError()); return false; diff --git a/src/Magnum/Platform/WindowlessEglApplication.h b/src/Magnum/Platform/WindowlessEglApplication.h index 601de0efa..fcf001b97 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.h +++ b/src/Magnum/Platform/WindowlessEglApplication.h @@ -115,6 +115,10 @@ class WindowlessEglContext { private: EGLDisplay _display{}; EGLContext _context{}; + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) + /* Needed only by SwiftShader, using EGL_NO_SURFACE everywhere else */ + EGLSurface _surface = EGL_NO_SURFACE; + #endif }; /**