mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-07 19:58:32 +09:00
284 lines
11 KiB
C
284 lines
11 KiB
C
// 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;
|
|
}
|