From 076beab650359838fa636996b90e38c5e336b5c0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Mon, 6 Feb 2023 15:06:07 +0000 Subject: [PATCH] Intercept EGL query and remove unsupported extensions. Closes #2830 * Since EGL is an Android API and highly likely to have unstable/unsupported/internal extensions, and also because we for the most part pass through the API apart from a couple of functions that we intercept but don't need to fully understand or process the attributes of, we take the approach of removing problematic extensions rather than only allowing extensions we know are safe. --- renderdoc/driver/gl/egl_dispatch_table.h | 2 +- renderdoc/driver/gl/egl_hooks.cpp | 58 +++++++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/renderdoc/driver/gl/egl_dispatch_table.h b/renderdoc/driver/gl/egl_dispatch_table.h index e953a8045..b85105a44 100644 --- a/renderdoc/driver/gl/egl_dispatch_table.h +++ b/renderdoc/driver/gl/egl_dispatch_table.h @@ -79,6 +79,7 @@ typedef PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC PFN_eglSwapBuffersWithDamageKHR; FUNC(CreatePlatformWindowSurface, false, false); \ FUNC(MakeCurrent, false, true); \ FUNC(SwapBuffers, false, true); \ + FUNC(QueryString, false, true); \ FUNC(PostSubBufferNV, true, false); \ FUNC(SwapBuffersWithDamageEXT, true, false); \ FUNC(SwapBuffersWithDamageKHR, true, false); @@ -94,7 +95,6 @@ typedef PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC PFN_eglSwapBuffersWithDamageKHR; FUNC(GetError, false, true); \ FUNC(Initialize, false, true); \ FUNC(QueryAPI, false, true); \ - FUNC(QueryString, false, true); \ FUNC(QuerySurface, false, true); \ FUNC(QueryContext, false, true); diff --git a/renderdoc/driver/gl/egl_hooks.cpp b/renderdoc/driver/gl/egl_hooks.cpp index 88de24b88..76046547a 100644 --- a/renderdoc/driver/gl/egl_hooks.cpp +++ b/renderdoc/driver/gl/egl_hooks.cpp @@ -22,10 +22,17 @@ * THE SOFTWARE. ******************************************************************************/ +#include "core/settings.h" #include "hooks/hooks.h" +#include "strings/string_utils.h" #include "egl_dispatch_table.h" #include "gl_driver.h" +RDOC_CONFIG(bool, Android_AllowAllEGLExtensions, false, + "Normally certain extensions are removed from the EGL extension string for " + "compatibility, but with this option that behaviour can be overridden and all " + "extensions will be reported."); + #if ENABLED(RDOC_POSIX) #include @@ -59,6 +66,11 @@ class EGLHook : LibraryHook { public: EGLHook() : driver(GetEGLPlatform()) {} + ~EGLHook() + { + for(auto it : extStrings) + SAFE_DELETE(it.second); + } void RegisterHooks(); RDCDriver activeAPI = RDCDriver::OpenGLES; @@ -69,6 +81,7 @@ public: std::map configs; std::map windows; std::map displays; + std::map extStrings; // indicates we're in a swap function, so don't process the swap any further if we recurse - could // happen due to driver implementation of one function calling another @@ -551,6 +564,45 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers_renderdoc_hooked(EGLDisplay dp } } +HOOK_EXPORT const char *EGLAPIENTRY eglQueryString_renderdoc_hooked(EGLDisplay dpy, EGLint name) +{ + if(RenderDoc::Inst().IsReplayApp()) + { + if(!EGL.QueryString) + EGL.PopulateForReplay(); + + return EGL.QueryString(dpy, name); + } + + EnsureRealLibraryLoaded(); + + SCOPED_LOCK(glLock); + + if(name == EGL_EXTENSIONS && !Android_AllowAllEGLExtensions()) + { + rdcstr *extStr = eglhook.extStrings[dpy]; + if(extStr == NULL) + extStr = eglhook.extStrings[dpy] = new rdcstr; + + const rdcstr implExtStr = EGL.QueryString(dpy, name); + + rdcarray exts; + split(implExtStr, exts, ' '); + + // We take the unusual approach here of explicitly _disallowing_ extensions only when we know + // they are unsupported. The main reason for this is because EGL is the android platform API and + // it may well be that undocumented internal or private extensions are important and should not + // be filtered out. Also since we have minimal interaction with the API as long as they don't + // affect the functions we care about for context management and swapping most extensions can be + // allowed silently. + exts.removeOne("EGL_KHR_no_config_context"); + + merge(exts, *extStr, ' '); + } + + return EGL.QueryString(dpy, name); +} + HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV_renderdoc_hooked(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, @@ -752,6 +804,11 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface sur return eglSwapBuffers_renderdoc_hooked(dpy, surface); } +HOOK_EXPORT const char *EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name) +{ + return eglQueryString_renderdoc_hooked(dpy, name); +} + HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height) { @@ -866,7 +923,6 @@ EGL_PASSTHRU_0(EGLint, eglGetError) EGL_PASSTHRU_3(EGLBoolean, eglInitialize, EGLDisplay, dpy, EGLint *, major, EGLint *, minor) EGL_PASSTHRU_4(EGLBoolean, eglQueryContext, EGLDisplay, dpy, EGLContext, ctx, EGLint, attribute, EGLint *, value) -EGL_PASSTHRU_2(const char *, eglQueryString, EGLDisplay, dpy, EGLint, name) EGL_PASSTHRU_4(EGLBoolean, eglQuerySurface, EGLDisplay, dpy, EGLSurface, surface, EGLint, attribute, EGLint *, value) EGL_PASSTHRU_1(EGLBoolean, eglTerminate, EGLDisplay, dpy)