From 101dbda8c34888bf2051c3c257da3a1702705ef9 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 18 Oct 2022 10:21:04 +0100 Subject: [PATCH] Handle GL hooks called during replay from injected code. Refs #2752 --- renderdoc/driver/gl/egl_hooks.cpp | 9 ++++++- renderdoc/driver/gl/gl_hooks.cpp | 43 +++++++++++++++++++------------ renderdoc/driver/gl/glx_hooks.cpp | 20 ++++++++++++-- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/renderdoc/driver/gl/egl_hooks.cpp b/renderdoc/driver/gl/egl_hooks.cpp index a3aa0cfc2a..09e69c0079 100644 --- a/renderdoc/driver/gl/egl_hooks.cpp +++ b/renderdoc/driver/gl/egl_hooks.cpp @@ -447,9 +447,16 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent_renderdoc_hooked(EGLDisplay di { if(RenderDoc::Inst().IsReplayApp()) { - if(!EGL.MakeCurrent) + if(!EGL.MakeCurrent || !EGL.GetProcAddress) EGL.PopulateForReplay(); + // populate GL function pointers now in case linked functions are called + if(EGL.GetProcAddress) + { + GL.PopulateWithCallback( + [](const char *funcName) -> void * { return (void *)EGL.GetProcAddress(funcName); }); + } + return EGL.MakeCurrent(display, draw, read, ctx); } diff --git a/renderdoc/driver/gl/gl_hooks.cpp b/renderdoc/driver/gl/gl_hooks.cpp index 369f924bea..7e5a0ac073 100644 --- a/renderdoc/driver/gl/gl_hooks.cpp +++ b/renderdoc/driver/gl/gl_hooks.cpp @@ -124,7 +124,6 @@ void DisableGLHooks() glhook.enabled = false; } -#if ENABLED(RDOC_WIN32) || ENABLED(RDOC_APPLE) || ENABLED(RDOC_SWITCH) template ret_type default_ret() { @@ -136,24 +135,34 @@ void default_ret() { } -// if we were injected and aren't ready to capture, skip out and call the real function -#define UNINIT_CALL(function, ...) \ - if(!glhook.enabled) \ - { \ - if(GL.function == NULL) \ - { \ - RDCERR("No function pointer for '%s' while uninitialised!", STRINGIZE(function)); \ - return default_ret(); \ - } \ - return GL.function(__VA_ARGS__); \ - } - -#else +template <> +const char *default_ret() +{ + return ""; +} -// nothing to do - we always assume we are ready to capture -#define UNINIT_CALL(function, ...) +template <> +const GLubyte *default_ret() +{ + return (const GLubyte *)""; +} -#endif +// on windows we can be injected and not ready to capture when we intercept a GL call. If that +// happens we need to skip and call the real function + +// on linux some systems inject external code into Qt which initialises GL behind our back. If this +// calls glXGetProcAddress it will get the real function pointers, but if it links against GL it +// will get routed here via our public exported symbols so we try to call the real function +#define UNINIT_CALL(function, ...) \ + if(!glhook.enabled) \ + { \ + if(GL.function == NULL) \ + { \ + RDCERR("No function pointer for '%s' while doing replay fallback!", STRINGIZE(function)); \ + return default_ret(); \ + } \ + return GL.function(__VA_ARGS__); \ + } DefineSupportedHooks(); DefineUnsupportedHooks(); diff --git a/renderdoc/driver/gl/glx_hooks.cpp b/renderdoc/driver/gl/glx_hooks.cpp index 5030fe8dfb..5bf2202eca 100644 --- a/renderdoc/driver/gl/glx_hooks.cpp +++ b/renderdoc/driver/gl/glx_hooks.cpp @@ -353,9 +353,17 @@ HOOK_EXPORT Bool glXMakeCurrent_renderdoc_hooked(Display *dpy, GLXDrawable drawa { if(RenderDoc::Inst().IsReplayApp()) { - if(!GLX.glXMakeCurrent) + if(!GLX.glXMakeCurrent || !GLX.glXGetProcAddress) GLX.PopulateForReplay(); + // populate GL function pointers now in case linked functions are called + if(GLX.glXGetProcAddress) + { + GL.PopulateWithCallback([](const char *funcName) -> void * { + return (void *)GLX.glXGetProcAddress((const GLubyte *)funcName); + }); + } + return GLX.glXMakeCurrent(dpy, drawable, ctx); } @@ -425,9 +433,17 @@ HOOK_EXPORT Bool glXMakeContextCurrent_renderdoc_hooked(Display *dpy, GLXDrawabl { if(RenderDoc::Inst().IsReplayApp()) { - if(!GLX.glXMakeContextCurrent) + if(!GLX.glXMakeContextCurrent || !GLX.glXGetProcAddress) GLX.PopulateForReplay(); + // populate GL function pointers now in case linked functions are called + if(GLX.glXGetProcAddress) + { + GL.PopulateWithCallback([](const char *funcName) -> void * { + return (void *)GLX.glXGetProcAddress((const GLubyte *)funcName); + }); + } + return GLX.glXMakeContextCurrent(dpy, draw, read, ctx); }