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 }; /**