diff --git a/selfcheck.c b/selfcheck.c new file mode 100644 index 00000000..959236a4 --- /dev/null +++ b/selfcheck.c @@ -0,0 +1,283 @@ +// selfcheck_egl_gl33_core_dlopen.c +// Build: gcc -O2 -Wall -Wextra selfcheck_egl_gl33_core_dlopen.c -o selfcheck -ldl +// Run: ./selfcheck /path/to/libmobileglues.so +// Notes: This program intentionally avoids linking against system libEGL/libGL. + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +// --- Minimal EGL types/constants (avoid including EGL headers) --- +typedef void* EGLDisplay; +typedef void* EGLConfig; +typedef void* EGLContext; +typedef void* EGLSurface; +typedef void* EGLClientBuffer; +typedef void (*__eglMustCastToProperFunctionPointerType)(void); + +typedef int32_t EGLint; +typedef uint32_t EGLBoolean; + +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +#define EGL_DEFAULT_DISPLAY ((void*)0) + +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + +#define EGL_SUCCESS 0x3000 + +#define EGL_EXTENSIONS 0x3055 +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_CLIENT_APIS 0x308D + +#define EGL_NONE 0x3038 + +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_RED_SIZE 0x3024 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 + +#define EGL_OPENGL_BIT 0x0008 +#define EGL_PBUFFER_BIT 0x0001 + +#define EGL_WIDTH 0x3057 +#define EGL_HEIGHT 0x3056 + +#define EGL_OPENGL_API 0x30A2 + +// EGL_KHR_create_context attributes +#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098 +#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB +#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD +#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001 +#define EGL_CONTEXT_FLAGS_KHR 0x30FC +#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001 +#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002 + +// --- Minimal GL constants (avoid including GL headers) --- +#define GL_VERSION 0x1F02 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C + +// --- Function pointer typedefs (EGL) --- +typedef EGLDisplay (*PFNEGLGETDISPLAY)(void* display_id); +typedef EGLBoolean (*PFNEGLINITIALIZE)(EGLDisplay dpy, EGLint* major, EGLint* minor); +typedef EGLBoolean (*PFNEGLTERMINATE)(EGLDisplay dpy); +typedef EGLint (*PFNEGLGETERROR)(void); +typedef const char*(*PFNEGLQUERYSTRING)(EGLDisplay dpy, EGLint name); +typedef EGLBoolean (*PFNEGLBINDAPI)(EGLint api); +typedef EGLBoolean (*PFNEGLCHOOSECONFIG)(EGLDisplay dpy, const EGLint* attrib_list, + EGLConfig* configs, EGLint config_size, EGLint* num_config); +typedef EGLContext (*PFNEGLCREATECONTEXT)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, + const EGLint* attrib_list); +typedef EGLSurface (*PFNEGLCREATEPBUFFERSURFACE)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list); +typedef EGLBoolean (*PFNEGLDESTROYSURFACE)(EGLDisplay dpy, EGLSurface surface); +typedef EGLBoolean (*PFNEGLDESTROYCONTEXT)(EGLDisplay dpy, EGLContext ctx); +typedef EGLBoolean (*PFNEGLMAKECURRENT)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); +typedef __eglMustCastToProperFunctionPointerType (*PFNEGLGETPROCADDRESS)(const char* procname); + +// surfaceless extension: eglCreatePbufferSurface can be skipped if makeCurrent allows EGL_NO_SURFACE, +// but we still attempt pbuffer if surfaceless fails. + +// --- Function pointer typedefs (GL) --- +typedef const unsigned char* (*PFNGLGETSTRING)(uint32_t name); + +// --- Helpers --- +static void die(const char* msg) { + fprintf(stderr, "FATAL: %s\n", msg); + exit(1); +} + +static void* must_dlsym(void* lib, const char* name) { + void* p = dlsym(lib, name); + if (!p) { + fprintf(stderr, "dlsym failed for %s: %s\n", name, dlerror()); + exit(1); + } + return p; +} + +static void print_egl_string(const char* label, PFNEGLQUERYSTRING eglQueryString, + EGLDisplay dpy, EGLint name) { + const char* s = eglQueryString(dpy, name); + printf("%s: %s\n", label, s ? s : "(null)"); +} + +int main(int argc, char** argv) { + if (argc != 2) { + fprintf(stderr, "Usage: %s /path/to/your_lib.so\n", argv[0]); + return 2; + } + + const char* lib_path = argv[1]; + printf("Loading EGL/GL compat library via dlopen: %s\n", lib_path); + + void* lib = dlopen(lib_path, RTLD_NOW | RTLD_LOCAL); + if (!lib) { + fprintf(stderr, "dlopen failed: %s\n", dlerror()); + return 1; + } + + // Load EGL entrypoints from YOUR library + PFNEGLGETDISPLAY eglGetDisplay = (PFNEGLGETDISPLAY)must_dlsym(lib, "eglGetDisplay"); + PFNEGLINITIALIZE eglInitialize = (PFNEGLINITIALIZE)must_dlsym(lib, "eglInitialize"); + PFNEGLTERMINATE eglTerminate = (PFNEGLTERMINATE)must_dlsym(lib, "eglTerminate"); + PFNEGLGETERROR eglGetError = (PFNEGLGETERROR)must_dlsym(lib, "eglGetError"); + PFNEGLQUERYSTRING eglQueryString = (PFNEGLQUERYSTRING)must_dlsym(lib, "eglQueryString"); + PFNEGLBINDAPI eglBindAPI = (PFNEGLBINDAPI)must_dlsym(lib, "eglBindAPI"); + PFNEGLCHOOSECONFIG eglChooseConfig = (PFNEGLCHOOSECONFIG)must_dlsym(lib, "eglChooseConfig"); + PFNEGLCREATECONTEXT eglCreateContext = (PFNEGLCREATECONTEXT)must_dlsym(lib, "eglCreateContext"); + PFNEGLCREATEPBUFFERSURFACE eglCreatePbufferSurface = + (PFNEGLCREATEPBUFFERSURFACE)must_dlsym(lib, "eglCreatePbufferSurface"); + PFNEGLDESTROYSURFACE eglDestroySurface = (PFNEGLDESTROYSURFACE)must_dlsym(lib, "eglDestroySurface"); + PFNEGLDESTROYCONTEXT eglDestroyContext = (PFNEGLDESTROYCONTEXT)must_dlsym(lib, "eglDestroyContext"); + PFNEGLMAKECURRENT eglMakeCurrent = (PFNEGLMAKECURRENT)must_dlsym(lib, "eglMakeCurrent"); + PFNEGLGETPROCADDRESS eglGetProcAddress = (PFNEGLGETPROCADDRESS)must_dlsym(lib, "eglGetProcAddress"); + + // 1) Get display + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (dpy == EGL_NO_DISPLAY) { + fprintf(stderr, "eglGetDisplay failed, eglGetError=0x%04x\n", eglGetError()); + return 1; + } + + // 2) Initialize EGL + EGLint maj = 0, min = 0; + if (!eglInitialize(dpy, &maj, &min)) { + fprintf(stderr, "eglInitialize failed, eglGetError=0x%04x\n", eglGetError()); + return 1; + } + printf("EGL initialized: %d.%d\n", maj, min); + + print_egl_string("EGL_VENDOR", eglQueryString, dpy, EGL_VENDOR); + print_egl_string("EGL_VERSION", eglQueryString, dpy, EGL_VERSION); + print_egl_string("EGL_CLIENT_APIS", eglQueryString, dpy, EGL_CLIENT_APIS); + print_egl_string("EGL_EXTENSIONS", eglQueryString, dpy, EGL_EXTENSIONS); + + // 3) Bind OpenGL API (desktop) + if (!eglBindAPI(EGL_OPENGL_API)) { + fprintf(stderr, "eglBindAPI(EGL_OPENGL_API) failed, eglGetError=0x%04x\n", eglGetError()); + eglTerminate(dpy); + return 1; + } + printf("eglBindAPI(EGL_OPENGL_API) OK\n"); + + // 4) Choose config that supports OpenGL + PBUFFER + const EGLint cfg_attribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + + EGLConfig cfg = 0; + EGLint num_cfg = 0; + if (!eglChooseConfig(dpy, cfg_attribs, &cfg, 1, &num_cfg) || num_cfg < 1) { + fprintf(stderr, "eglChooseConfig failed/none found, eglGetError=0x%04x, num_cfg=%d\n", + eglGetError(), num_cfg); + eglTerminate(dpy); + return 1; + } + printf("eglChooseConfig OK (num_cfg=%d)\n", num_cfg); + + // 5) Create OpenGL 3.3 core context (KHR_create_context) + const EGLint ctx_attribs[] = { + EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_MINOR_VERSION_KHR, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR, + // Optional flags: + // EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR, + EGL_NONE + }; + + EGLContext ctx = eglCreateContext(dpy, cfg, EGL_NO_CONTEXT, ctx_attribs); + if (ctx == EGL_NO_CONTEXT) { + fprintf(stderr, "eglCreateContext(GL 3.3 core) failed, eglGetError=0x%04x\n", eglGetError()); + fprintf(stderr, "Hint: check EGL_KHR_create_context & EGL_OPENGL_API support.\n"); + eglTerminate(dpy); + return 1; + } + printf("eglCreateContext(GL 3.3 core) OK\n"); + + // 6) Try surfaceless makeCurrent first + EGLBoolean mc_ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx); + if (!mc_ok) { + EGLint err = eglGetError(); + printf("Surfaceless eglMakeCurrent failed (err=0x%04x). Falling back to Pbuffer.\n", err); + + const EGLint pb_attribs[] = { + EGL_WIDTH, 64, + EGL_HEIGHT, 64, + EGL_NONE + }; + + EGLSurface surf = eglCreatePbufferSurface(dpy, cfg, pb_attribs); + if (surf == EGL_NO_SURFACE) { + fprintf(stderr, "eglCreatePbufferSurface failed, eglGetError=0x%04x\n", eglGetError()); + eglDestroyContext(dpy, ctx); + eglTerminate(dpy); + return 1; + } + + if (!eglMakeCurrent(dpy, surf, surf, ctx)) { + fprintf(stderr, "eglMakeCurrent(pbuffer) failed, eglGetError=0x%04x\n", eglGetError()); + eglDestroySurface(dpy, surf); + eglDestroyContext(dpy, ctx); + eglTerminate(dpy); + return 1; + } + printf("eglMakeCurrent(pbuffer) OK\n"); + + // Load glGetString from eglGetProcAddress (avoid linking libGL) + PFNGLGETSTRING glGetString = + (PFNGLGETSTRING)(uintptr_t)eglGetProcAddress("glGetString"); + if (!glGetString) die("eglGetProcAddress(glGetString) returned NULL"); + + printf("GL_VENDOR: %s\n", (const char*)glGetString(GL_VENDOR)); + printf("GL_RENDERER: %s\n", (const char*)glGetString(GL_RENDERER)); + printf("GL_VERSION: %s\n", (const char*)glGetString(GL_VERSION)); + printf("GLSL: %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); + + // Cleanup pbuffer path + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(dpy, surf); + } else { + printf("eglMakeCurrent(surfaceless) OK\n"); + + PFNGLGETSTRING glGetString = + (PFNGLGETSTRING)(uintptr_t)eglGetProcAddress("glGetString"); + if (!glGetString) die("eglGetProcAddress(glGetString) returned NULL"); + + printf("GL_VENDOR: %s\n", (const char*)glGetString(GL_VENDOR)); + printf("GL_RENDERER: %s\n", (const char*)glGetString(GL_RENDERER)); + printf("GL_VERSION: %s\n", (const char*)glGetString(GL_VERSION)); + printf("GLSL: %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); + + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + } + + // Destroy context & terminate + eglDestroyContext(dpy, ctx); + eglTerminate(dpy); + dlclose(lib); + + printf("Self-check finished OK.\n"); + return 0; +}