diff --git a/doc/changelog.dox b/doc/changelog.dox index e0e910d69..e648d3d87 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -136,6 +136,9 @@ See also: - A new @cpp "angle-chatty-shader-compiler" @ce workaround for silencing useless linker output on ANGLE. See @ref opengl-workarounds for more information. +- A new @cpp "android-generic-hostname-might-be-swiftshader" @ce workaround + needed for testing against Android Emulator SwiftShader GPU. See + @ref opengl-workarounds for more information. @subsubsection changelog-latest-new-math Math library diff --git a/src/Magnum/GL/Implementation/driverSpecific.cpp b/src/Magnum/GL/Implementation/driverSpecific.cpp index 16333caeb..d5c192741 100644 --- a/src/Magnum/GL/Implementation/driverSpecific.cpp +++ b/src/Magnum/GL/Implementation/driverSpecific.cpp @@ -44,6 +44,18 @@ using namespace Containers::Literals; /* Search the code for the following strings to see where they are implemented */ constexpr Containers::StringView KnownWorkarounds[]{ /* [workarounds] */ +#if defined(CORRADE_TARGET_ANDROID) && defined(MAGNUM_TARGET_GLES) +/* Android Emulator can run with a SwiftShader GPU and thus needs some of the + SwiftShader context creation workarounds. However, it's impossible to + detect, as EGL_VERSION is always "1.4 Android META-EGL" and EGL_VENDOR + always "Android". As there's nothing that would hint at SwiftShader being + used, we conservatively assume every emulator can be a SwiftShader. But + that's not easy either, the only vague hint that we're dealing with an + emulator is the HOSTNAME env var, which is set to e.g. generic_x86, but to + e.g. HWVTR on a device, so try that. */ +"android-generic-hostname-might-be-swiftshader"_s, +#endif + #if defined(MAGNUM_TARGET_GLES) && !defined(MAGNUM_TARGET_WEBGL) /* ANGLE's shader linker insists on returning a message consisting of a single newline on success, causing annoying noise in the console. Similar to @@ -212,13 +224,18 @@ constexpr Containers::StringView KnownWorkarounds[]{ #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 */ +/* Empty EGL_CONTEXT_FLAGS_KHR cause SwiftShader 3.3 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 + Version 4.1 suffers from the same thing, but 4.0 on Android not, for some + reason. */ "swiftshader-no-empty-egl-context-flags"_s, /* SwiftShader 3.3.0.1 crashes deep inside eglMakeCurrent() when using - EGL_NO_SURFACE. Supplying a 32x32 PBuffer to work around that. */ + EGL_NO_SURFACE. Supplying a 32x32 PBuffer to work around that. (Android's) + SwiftShader 4.0 needs it too, but doesn't crash, only fails to make the + context current with EGL_BAD_MATCH. Version 4.1 doesn't seem to need this + workaround anymore. */ "swiftshader-egl-context-needs-pbuffer"_s, #endif diff --git a/src/Magnum/Platform/WindowlessEglApplication.cpp b/src/Magnum/Platform/WindowlessEglApplication.cpp index 081004e83..a4f99d164 100644 --- a/src/Magnum/Platform/WindowlessEglApplication.cpp +++ b/src/Magnum/Platform/WindowlessEglApplication.cpp @@ -364,7 +364,11 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G /* 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 */ + work either: https://github.com/google/swiftshader/blob/5fb5e817a20d3e60f29f7338493f922b5ac9d7c4/src/OpenGL/libEGL/libEGL.cpp#L794-L8104 + + Interestingly, on Android Emulator SwiftShader 4.0 this workaround isn't + needed, so we don't need to use the isSwiftShader variable (from below) + in this case. */ if(!(UnsignedLong(flags) & 0xffffffffu) && version.contains("SwiftShader"_s) && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("swiftshader-no-empty-egl-context-flags"_s))) { auto& contextFlags = attributes[nextAttribute - 2]; CORRADE_INTERNAL_ASSERT(contextFlags == EGL_CONTEXT_FLAGS_KHR); @@ -486,9 +490,27 @@ WindowlessEglContext::WindowlessEglContext(const Configuration& configuration, G } #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.contains("SwiftShader"_s) && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("swiftshader-egl-context-needs-pbuffer"_s))) { + /* Android Emulator can run with a SwiftShader GPU and thus needs some of + the SwiftShader context creation workarounds. However, it's impossible + to detect, as EGL_VERSION is always "1.4 Android META-EGL" and + EGL_VENDOR always "Android". As there's nothing that would hint at + SwiftShader being used, we conservatively assume every emulator can be a + SwiftShader. But that's not easy either, the only vague hint that we're + dealing with an emulator is the HOSTNAME env var, which is set to e.g. + generic_x86, but to e.g. HWVTR on a device, so try that. */ + const bool isSwiftShader = + #ifndef CORRADE_TARGET_ANDROID + version.contains("SwiftShader"_s) + #else + Containers::StringView{std::getenv("HOSTNAME")}.contains("generic"_s) && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("android-generic-hostname-might-be-swiftshader"_s)) + #endif + ; + + /* SwiftShader 3.3 needs some pbuffer, otherwise it crashes somewhere deep + inside when making the context current. (Android's) SwiftShader 4.0 + needs it too, but doesn't crash, only fails to make the context current + with EGL_BAD_MATCH. Version 4.1 doesn't need this workaround anymore. */ + if(isSwiftShader && (!magnumContext || !magnumContext->isDriverWorkaroundDisabled("swiftshader-egl-context-needs-pbuffer"_s))) { EGLint surfaceAttributes[] = { EGL_WIDTH, 32, EGL_HEIGHT, 32,