[Chore]: small program to do a tiny self-check

This commit is contained in:
2026-01-17 11:23:36 +08:00
parent 80bb46cbb9
commit 35fd55d4be
+283
View File
@@ -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 <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// --- 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;
}