baldurk / renderdoc

RenderDoc is a stand-alone graphics debugging tool.
https://renderdoc.org
MIT License
8.99k stars 1.35k forks source link

renderdoccmd fails to capture when using eglfs Qt qpa. #2450

Closed jjcasmar closed 2 years ago

jjcasmar commented 2 years ago

Description

When using eglfs Qt qpa on an embedded platform, renderdocmd is unable to capture a trace due to unresolved functions (log below).

Steps to reproduce

On an embedded linux platform (I have tried several iMX8 and Rpi4), try to run renderdoccmd capture yourApp. Rendercapture shows a bunch of unresolved functions and then the application crashes. I have tested with several applications, both my own applications and also with Qt OpenGL examples.

Environment

I have been using a linux image built with yocto. RenderDoc version: Tested with 1.7 and 1.17, both with same result Operating System: Linux Graphics API: GLES 3.1 Driver: Vivante GC7000UL

apitrace shows a similar behavior, described in this patch https://github.com/dangelog/apitrace/commit/1f42a3484e97a2008ad43891c17dc9fcaee60f67

[     2] Failed EGL API GetProcAddress: eglUnlockSurfaceKHR !
[     3] Failed EGL API GetProcAddress: eglCreateImageKHR !
[     4] Failed EGL API GetProcAddress: eglDestroyImageKHR !
[     5] Failed EGL API GetProcAddress: eglCreateSyncKHR !
[     6] Failed EGL API GetProcAddress: eglDestroySyncKHR !
[     7] Failed EGL API GetProcAddress: eglClientWaitSyncKHR !
[     8] Failed EGL API GetProcAddress: eglGetSyncAttribKHR !
[     9] Failed EGL API GetProcAddress: eglSignalSyncKHR !
[    10] Failed EGL API GetProcAddress: eglWaitSyncKHR !
[    11] Failed EGL API GetProcAddress: eglGetPlatformDisplayEXT !
[    12] Failed EGL API GetProcAddress: eglCreatePlatformWindowSurfaceEXT !
[    13] Failed EGL API GetProcAddress: eglCreatePlatformPixmapSurfaceEXT !
[    14] Failed EGL API GetProcAddress: eglBindWaylandDisplayWL !
[    15] Failed EGL API GetProcAddress: eglUnbindWaylandDisplayWL !
[    16] Failed EGL API GetProcAddress: eglQueryWaylandBufferWL !
[    17] Failed EGL API GetProcAddress: eglUpdateWaylandBufferWL !
[    18] Failed EGL API GetProcAddress: eglDupNativeFenceFDANDROID !
[    19] Failed EGL API GetProcAddress: eglSetDamageRegionKHR !
[    20] Failed EGL API GetProcAddress: eglQueryDmaBufFormatsEXT !
[    21] Failed EGL API GetProcAddress: eglQueryDmaBufModifiersEXT !
[    22] Failed EGL API GetProcAddress: eglPatchID !
[    23] Failed ES_Common API GetProcAddress: forward_glActiveTexture !
[    24] Failed ES_Common API GetProcAddress: forward_glBindBuffer !
[    25] Failed ES_Common API GetProcAddress: forward_glBindTexture !
[    26] Failed ES_Common API GetProcAddress: forward_glBlendFunc !
[    27] Failed ES_Common API GetProcAddress: forward_glBufferData !
[    28] Failed ES_Common API GetProcAddress: forward_glBufferSubData !
[    29] Failed ES_Common API GetProcAddress: forward_glClear !
[    30] Failed ES_Common API GetProcAddress: forward_glClearColor !
[    31] Failed ES_Common API GetProcAddress: forward_glClearDepthf !
[    32] Failed ES_Common API GetProcAddress: forward_glClearStencil !
[    33] Failed ES_Common API GetProcAddress: forward_glColorMask !
[    34] Failed ES_Common API GetProcAddress: forward_glCompressedTexImage2D !
[    35] Failed ES_Common API GetProcAddress: forward_glCompressedTexSubImage2D !
[    36] Failed ES_Common API GetProcAddress: forward_glCopyTexImage2D !
[    37] Failed ES_Common API GetProcAddress: forward_glCopyTexSubImage2D !
[    38] Failed ES_Common API GetProcAddress: forward_glCullFace !
[    39] Failed ES_Common API GetProcAddress: forward_glDeleteBuffers !
[    40] Failed ES_Common API GetProcAddress: forward_glDeleteTextures !
[    41] Failed ES_Common API GetProcAddress: forward_glDepthFunc !
[    42] Failed ES_Common API GetProcAddress: forward_glDepthMask !
[    43] Failed ES_Common API GetProcAddress: forward_glDepthRangef !
[    44] Failed ES_Common API GetProcAddress: forward_glDisable !
[    45] Failed ES_Common API GetProcAddress: forward_glDrawArrays !
[    46] Failed ES_Common API GetProcAddress: forward_glDrawElements !
[    47] Failed ES_Common API GetProcAddress: forward_glEnable !
[    48] Failed ES_Common API GetProcAddress: forward_glFinish !
[    49] Failed ES_Common API GetProcAddress: forward_glFlush !
[    50] Failed ES_Common API GetProcAddress: forward_glFrontFace !
[    51] Failed ES_Common API GetProcAddress: forward_glGenBuffers !
[    52] Failed ES_Common API GetProcAddress: forward_glGenTextures !
[    53] Failed ES_Common API GetProcAddress: forward_glGetBooleanv !
[    54] Failed ES_Common API GetProcAddress: forward_glGetBufferParameteriv !
[    55] Failed ES_Common API GetProcAddress: forward_glGetError !
[    56] Failed ES_Common API GetProcAddress: forward_glGetFloatv !
[    57] Failed ES_Common API GetProcAddress: forward_glGetIntegerv !
[    58] Failed ES_Common API GetProcAddress: forward_glGetPointerv !
[    59] Failed ES_Common API GetProcAddress: forward_glGetString !
[    60] Failed ES_Common API GetProcAddress: forward_glGetTexParameterfv !
[    61] Failed ES_Common API GetProcAddress: forward_glGetTexParameteriv !
[    62] Failed ES_Common API GetProcAddress: forward_glHint !
[    63] Failed ES_Common API GetProcAddress: forward_glIsBuffer !
[    64] Failed ES_Common API GetProcAddress: forward_glIsEnabled !
[    65] Failed ES_Common API GetProcAddress: forward_glIsTexture !
[    66] Failed ES_Common API GetProcAddress: forward_glLineWidth !
[    67] Failed ES_Common API GetProcAddress: forward_glPixelStorei !
[    68] Failed ES_Common API GetProcAddress: forward_glPolygonOffset !
[    69] Failed ES_Common API GetProcAddress: forward_glReadPixels !
[    70] Failed ES_Common API GetProcAddress: forward_glSampleCoverage !
[    71] Failed ES_Common API GetProcAddress: forward_glScissor !
[    72] Failed ES_Common API GetProcAddress: forward_glStencilFunc !
[    73] Failed ES_Common API GetProcAddress: forward_glStencilMask !
[    74] Failed ES_Common API GetProcAddress: forward_glStencilOp !
[    75] Failed ES_Common API GetProcAddress: forward_glTexImage2D !
[    76] Failed ES_Common API GetProcAddress: forward_glTexParameterf !
[    77] Failed ES_Common API GetProcAddress: forward_glTexParameterfv !
[    78] Failed ES_Common API GetProcAddress: forward_glTexParameteri !
[    79] Failed ES_Common API GetProcAddress: forward_glTexParameteriv !
[    80] Failed ES_Common API GetProcAddress: forward_glTexSubImage2D !
[    81] Failed ES_Common API GetProcAddress: forward_glViewport !
[    82] Failed ES_Common API GetProcAddress: forward_glMapBufferOES !
[    83] Failed ES_Common API GetProcAddress: forward_glUnmapBufferOES !
[    84] Failed ES_Common API GetProcAddress: forward_glEGLImageTargetTexture2DOES !
[    85] Failed ES_Common API GetProcAddress: forward_glEGLImageTargetRenderbufferStorageOES !
[    86] Failed ES_Common API GetProcAddress: forward_glMultiDrawArraysEXT !
[    87] Failed ES_Common API GetProcAddress: forward_glMultiDrawElementsEXT !
[    88] Failed ES_Common API GetProcAddress: forward_glTexDirectVIV !
[    89] Failed ES_Common API GetProcAddress: forward_glTexDirectInvalidateVIV !
[    90] Failed ES_Common API GetProcAddress: forward_glTexDirectVIVMap !
[    91] Failed ES_Common API GetProcAddress: forward_glTexDirectTiledMapVIV !
[    92] Failed GLES32 API GetProcAddress: glTexDirectVIV !
[    93] Failed GLES32 API GetProcAddress: glTexDirectInvalidateVIV !
[    94] Failed GLES32 API GetProcAddress: glTexDirectVIVMap !
[    95] Failed GLES32 API GetProcAddress: glTexDirectTiledMapVIV !
[    96] Failed ES Common GLES2X API GetProcAddress: glTexDirectVIV !
jjcasmar commented 2 years ago

apitrace issue was solved with this patch, which may help to solve this similar issue in renderdoc

diff --git i/dispatch/glproc.py w/dispatch/glproc.py
index f26a4f7d..c2701228 100644
--- i/dispatch/glproc.py
+++ w/dispatch/glproc.py
@@ -590,6 +590,7 @@ if __name__ == '__main__':
     print
     print 'void * _getPublicProcAddress(const char *procName);'
     print 'void * _getPrivateProcAddress(const char *procName);'
+    print 'void * _eglGetProcAddress_KDAB(const char *procName, void (* (_eglGetProcAddress)(const char*))());'
     print
     dispatcher = GlDispatcher()
     print
diff --git i/dispatch/glproc_egl.cpp w/dispatch/glproc_egl.cpp
index 07714ae8..40119118 100644
--- i/dispatch/glproc_egl.cpp
+++ w/dispatch/glproc_egl.cpp
@@ -72,10 +72,12 @@ _getPublicProcAddress(const char *procName)
      * symbols are exported by multiple APIs/SOs, and it's not trivial to
      * determine which API/SO we should get the current symbol from.
      */
+    // egl
     proc = dlsym(RTLD_NEXT, procName);
     if (proc) {
         return proc;
     }
+    os::log("apitrace: _getPublicProcAddress(%s) couldn't dlsym(RTLD_NEXT)\n", procName);

     /*
      * dlsym(RTLD_NEXT, ...) will fail when the SO containing the symbol was
@@ -87,13 +89,16 @@ _getPublicProcAddress(const char *procName)
      */

     if (procName[0] == 'e' && procName[1] == 'g' && procName[2] == 'l') {
+        os::log("apitrace: loading libEGL ourselves\n");
         static void *libEGL = NULL;
         if (!libEGL) {
             libEGL = _dlopen("libEGL.so", RTLD_LOCAL | RTLD_LAZY);
             if (!libEGL) {
+                os::log("apitrace: loading libEGL ourselves didn't work: %s\n", dlerror());
                 return NULL;
             }
         }
+        os::log("apitrace: dlsym(libEGL, \"%s\")\n", procName);
         return dlsym(libEGL, procName);
     }

@@ -114,12 +119,12 @@ _getPublicProcAddress(const char *procName)
      *
      * See https://github.com/apitrace/apitrace/issues/301#issuecomment-68532248
      */
-    if (strcmp(procName, "eglGetProcAddress") != 0) {
-        proc = (void *) _eglGetProcAddress(procName);
-        if (proc) {
-            return proc;
-        }
-    }
+//    if (strcmp(procName, "eglGetProcAddress") != 0) {
+//        proc = (void *) _eglGetProcAddress(procName);
+//        if (proc) {
+//            return proc;
+//        }
+//    }

     /*
      * TODO: We could futher mitigate against using the wrong SO by:
@@ -128,14 +133,17 @@ _getPublicProcAddress(const char *procName)
      */

     if (procName[0] == 'g' && procName[1] == 'l') {
+        os::log("apitrace: looking up gl function by loading lib ourselves\n");
         /* TODO: Use GLESv1/GLESv2 on a per-context basis. */

         static void *libGLESv2 = NULL;
         if (!libGLESv2) {
+            os::log("apitrace: loading libGLESv2\n");
             libGLESv2 = _dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY);
         }
         if (libGLESv2) {
             proc = dlsym(libGLESv2, procName);
+            os::log("apitrace: dlsym(libGLESv2, %s) = %p\n", procName, proc);
         }
         if (proc) {
             return proc;
@@ -156,6 +164,44 @@ _getPublicProcAddress(const char *procName)
     return NULL;
 }

+void * _eglGetProcAddress_KDAB(const char *procName, void (* (_eglGetProcAddress)(const char*))())
+{
+    void * proc;
+    os::log("apitrace: KDAB eglGetProcAddress\n");
+    if (procName[0] == 'g' && procName[1] == 'l') {
+        os::log("apitrace: looking up gl function by loading lib ourselves\n");
+        /* TODO: Use GLESv1/GLESv2 on a per-context basis. */
+
+        static void *libGLESv2 = NULL;
+        if (!libGLESv2) {
+            os::log("apitrace: loading libGLESv2\n");
+            libGLESv2 = _dlopen("libGLESv2.so", RTLD_LOCAL | RTLD_LAZY);
+        }
+        if (libGLESv2) {
+            proc = dlsym(libGLESv2, procName);
+            os::log("apitrace: dlsym(libGLESv2, %s) = %p\n", procName, proc);
+        }
+        if (proc) {
+            return proc;
+        }
+
+        static void *libGLESv1 = NULL;
+        if (!libGLESv1) {
+            libGLESv1 = _dlopen("libGLESv1_CM.so", RTLD_LOCAL | RTLD_LAZY);
+        }
+        if (libGLESv1) {
+            proc = dlsym(libGLESv1, procName);
+        }
+        if (proc) {
+            return proc;
+        }
+    }
+
+    os::log("apitrace: defaulting to original eglGetProcAddress\n");
+    proc = (void*)_eglGetProcAddress(procName);
+    return proc;
+}
+
 /*
  * Lookup a private EGL/GL/GLES symbol
  *
diff --git i/dispatch/glproc_gl.cpp w/dispatch/glproc_gl.cpp
index 7d162dab..7b094f6c 100644
--- i/dispatch/glproc_gl.cpp
+++ w/dispatch/glproc_gl.cpp
@@ -148,7 +148,7 @@ _getPrivateProcAddress(const char *procName)

 static inline void
 logSymbol(const char *name, void *ptr) {
-    if (0) {
+    if (1) {
         if (ptr) {
             Dl_info info;
             if (ptr && dladdr(ptr, &info)) {
diff --git i/wrappers/gltrace.py w/wrappers/gltrace.py
index 6f96572e..d4a11adc 100644
--- i/wrappers/gltrace.py
+++ w/wrappers/gltrace.py
@@ -853,13 +853,15 @@ class GlTracer(Tracer):
                     print '    } else if (strcmp("%s", (const char *)%s) == 0) {' % (marker_function, nameArg)
                     print '        _result = (%s)&%s;' % (function.type, marker_function)
             print '    } else {'
-            Tracer.doInvokeFunction(self, function)
+#            Tracer.doInvokeFunction(self, function)
+            print '     _result = (__eglMustCastToProperFunctionPointerType)_eglGetProcAddress_KDAB(procname, _eglGetProcAddress);';

             # Replace function addresses with ours
             # XXX: Doing this here instead of wrapRet means that the trace will
             # contain the addresses of the wrapper functions, and not the real
             # functions, but in practice this should make no difference.
             if function.name in self.getProcAddressFunctionNames:
+                print '    os::log("apitrace: got %p for %s\\n", _result, procname);'
                 print '    _result = _wrapProcAddress(%s, _result);' % (nameArg,)

             print '    }'
baldurk commented 2 years ago

Sorry, you've included a lot of information that I'm not familiar with so you'll need to explain it to me in more detail. What is "eglds Qt qpa" ? You also mention under steps to reproduce that "Rendercapture" displays errors about unresolved functions but I don't know what that is. Is that the application that you're capturing, and is it something that's available or that I could run myself to test with?

You've mentioned a log, but the log you've include is not from RenderDoc so I don't know what it is. Can you attach the RenderDoc log? You mention using renderdoccmd, is this on an Android system?

Are you able to run your program on a non-embedded linux system and reproduce the problem? RenderDoc is not supported on anything except x86-64 for linux, ARM is only supported on Android, so from what you're describing if this issue only replicates on ARM systems then it might be an architecture/platform specific problem and not something I can look into.

jjcasmar commented 2 years ago

eglfs Qt qpa is a platform integration plugin to abstract the underlying window system of a platform (X, wayland, egl...) in Qt. Basically, on an embedded device, when you are not running a windows manager, you can use eglfs to render to fullscreen a Qt application. (https://doc.qt.io/qt-5/embedded-linux.html). I doubt you can run it yourself, at least not without a lot of work. Maybe I can share a rpi4/3 image with everything needed if you have a spare one to test if you want.

The log I have posted is the output I am getting when I try to run the application. How can I get a RenderDoc log?

No, its not android, its a Linux system running on an ARM platform, so I guess it is an unsupported platform. Feel free to close the issue in that case.

baldurk commented 2 years ago

Yes sorry, if you're running on ARM linux that's not supported at the moment so there may be bugs. In addition I would imagine there are platform-specific details and requirements for embedded devices which are not handled on top of that. I don't have any such device to test on even if it were supported I'm afraid.