diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java index 2be79916d..6dab57082 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/JREUtils.java @@ -210,7 +210,6 @@ public class JREUtils { envMap.put("force_glsl_extensions_warn", "true"); envMap.put("allow_higher_compat_version", "true"); envMap.put("allow_glsl_extension_directive_midshader", "true"); - envMap.put("MESA_LOADER_DRIVER_OVERRIDE", "zink"); envMap.put("VTEST_SOCKET_NAME", new File(Tools.DIR_CACHE, ".virgl_test").getAbsolutePath()); envMap.put("LD_LIBRARY_PATH", LD_LIBRARY_PATH); @@ -254,7 +253,12 @@ public class JREUtils { Tools.useSFPEW = false; } if (LOCAL_RENDERER.equals("opengles3_desktopgl_zink_kopper")){ - envMap.put("POJAVEXEC_EGL","libEGL_mesa.so"); // Use Mesa EGL + envMap.put("POJAVEXEC_EGL", "libEGL_mesa.so"); // Use Mesa EGL + if (Tools.shouldUseUBWC()) envMap.put("FD_DEV_FEATURES", "enable_tp_ubwc_flag_hint=1"); // Turnip fix for OneUI rendering issues + } + if (LOCAL_RENDERER.equals("opengles3_desktopgl_freedreno")){ + envMap.put("POJAVEXEC_EGL", "libEGL_mesa.so"); // Use Mesa EGL + Tools.useSFPEW = false; if (Tools.shouldUseUBWC()) envMap.put("FD_DEV_FEATURES", "enable_tp_ubwc_flag_hint=1"); // Turnip fix for OneUI rendering issues } if (LOCAL_RENDERER.toLowerCase().contains("zink")){ @@ -544,6 +548,7 @@ public class JREUtils { renderLibrary = "libng_gl4es.so"; break; case "vulkan_zink": renderLibrary = "libOSMesa.so"; break; case "opengles_mobileglues": renderLibrary = "libmobileglues.so"; break; + case "opengles3_desktopgl_freedreno": case "opengles3_desktopgl_zink_kopper": renderLibrary = "libEGL_mesa.so"; break; case "opengles3_ltw" : renderLibrary = "libltw.so"; break; case "opengles_system_gles" : return null; // Literally nothing, this is for system GLES. diff --git a/app_pojavlauncher/src/main/jni/Android.mk b/app_pojavlauncher/src/main/jni/Android.mk index d376ecf4a..6c1d391e7 100644 --- a/app_pojavlauncher/src/main/jni/Android.mk +++ b/app_pojavlauncher/src/main/jni/Android.mk @@ -77,7 +77,8 @@ include $(BUILD_SHARED_LIBRARY) include $(CLEAR_VARS) LOCAL_MODULE := linkerhook LOCAL_C_INCLUDES := $(LOCAL_PATH)/include -LOCAL_SRC_FILES := driver_helper/internal_android_dlopen_hook/turnip/hook.c +LOCAL_SRC_FILES := \ + driver_helper/internal_android_dlopen_hook/turnip/hook.c # If you add LOCAL_SHARED_LIBRARIES here, it might load those NEEDED as duplicates # in wherever namespace this is put inside of. Please just do not. # Use dlopen if at all possible, the plt/got is a lie!! diff --git a/app_pojavlauncher/src/main/jni/android_linker_namespace_bypass/nsbypass.c b/app_pojavlauncher/src/main/jni/android_linker_namespace_bypass/nsbypass.c index 094833194..53a8b6053 100644 --- a/app_pojavlauncher/src/main/jni/android_linker_namespace_bypass/nsbypass.c +++ b/app_pojavlauncher/src/main/jni/android_linker_namespace_bypass/nsbypass.c @@ -395,19 +395,20 @@ bool test_namespace_funcs(private_namespace_funcs nsFuncs) { escapeNs = nsFuncs.create_namespace( "g_default_namespace_copy", NULL, - NULL, + SYSTEM_LIBS_PATH, ANDROID_NAMESPACE_TYPE_SHARED, + SYSTEM_LIBS_PATH, NULL, - NULL, - &dlopen); + &dlopen); // This address is libdl.so, which should resolve to g_default_namespace if (escapeNs) { LOGI("android_create_namespace successfully made escapeNs"); } else { LOGE("android_create_namespace failed to create namespace escapeNs, testing cannot continue. FAIL"); return false; } - // This is a memory leak, but its only once and for the process lifetime. - // AFAIK there is no way to get rid of a namespace sadly. + // This is a memory leak, but its only once and for the process lifetime. So might as well make + // it useful if it's gonna be leaking. + // AFAIK there is no way to get rid of a namespace sadly. If you know how, make an issue. struct android_namespace_t *testNs = nsFuncs.create_namespace( "g_default_namespace_copy", NULL, @@ -453,7 +454,7 @@ struct android_namespace_t* escapeNs; * Resolves all the global externs at load time, so they should always be available. * Fails hard if any of them are not. */ -__attribute__((constructor)) void resolve_global_symbols() { +__attribute__((constructor)) static void resolve_global_symbols() { // NOTE: Tests are fast enough. Probably still disable tho. g_privateDlFuncs = get_private_dl_functions(); test_dlfuncs(g_privateDlFuncs); @@ -468,14 +469,14 @@ __attribute__((constructor)) void resolve_global_symbols() { LOGE("Failed to resolve Android linker namespace functions! Cannot run nsbypass."); return; } - + // Create if not yet, which is the case if tests are disabled if (!escapeNs){ escapeNs = g_linkerFuncs.create_namespace( "g_default_namespace_copy", NULL, - NULL, + SYSTEM_LIBS_PATH, ANDROID_NAMESPACE_TYPE_SHARED, - NULL, + SYSTEM_LIBS_PATH, NULL, &dlopen); if (!escapeNs) { @@ -485,6 +486,16 @@ __attribute__((constructor)) void resolve_global_symbols() { } } +/* + Note: + You may have found that escapeNs does not have search paths within your app native dir and thus + cannot properly resolve any NEEDED's from there. Make your own namespace. I suggest creating + a SHARED ns with parent escapeNs. Simply add your nativeLibraryDir to default_library_path and + it will be appended to the list that it will search for NEEDEDs! + + or yknow, preload them. dlopen them before the lib that needs them. + */ + // dlopen in a specific namespace void* linker_ns_dlopen(const char* name, int flag, struct android_namespace_t* ns) { if (!ns) return NULL; diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.c b/app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.c index a71d0615c..3a9144965 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/egl_loader.c @@ -6,7 +6,9 @@ #include #include #include "egl_loader.h" +#include "global_state.h" #include "loader_dlopen.h" +#include "android_linker_namespace_bypass/nsbypass.h" EGLBoolean (*eglMakeCurrent_p) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); EGLBoolean (*eglDestroyContext_p) (EGLDisplay dpy, EGLContext ctx); @@ -32,15 +34,27 @@ EGLBoolean (*eglQuerySurface_p)( EGLDisplay display, EGLint * value); __eglMustCastToProperFunctionPointerType (*eglGetProcAddress_p) (const char *procname); +struct android_namespace_t* app_escapeNs; + bool dlsym_EGL() { char* gles = getenv("LIBGL_GLES"); char* eglName = (strncmp(gles ? gles : "", "libGLESv2_angle.so", 18) == 0) ? "libEGL_angle.so" : getenv("POJAVEXEC_EGL"); -// // Kopper needs this -// if (eglName != NULL && strncmp(eglName, "libEGL_mesa.so", 14) == 0) { -// void* cutils_handle = loader_dlopen("libcutils.so", "libcutils.so", RTLD_GLOBAL|RTLD_NOW); -// if(cutils_handle == NULL) return false; -// } void* dl_handle = loader_dlopen(eglName,"libEGL.so", RTLD_LOCAL|RTLD_LAZY); + // Mesa renderers that are also GPU drivers need this + if (eglName != NULL && strncmp(eglName, "libEGL_mesa.so", 14) == 0) { + // Not sure where to put this because pojavexec is shit + if (!app_escapeNs) + app_escapeNs = g_linkerFuncs.create_namespace( + "app-escapeNs", + NULL, + getenv("POJAV_NATIVEDIR"), // append to search path! + ANDROID_NAMESPACE_TYPE_SHARED, // Inherit from escapeNs paths + getenv("POJAV_NATIVEDIR"), // not needed, useless for non-isolate + escapeNs, // Inherit from escapeNs so we get the system lib paths too + __builtin_return_address(0) + ); + dl_handle = linker_ns_dlopen(eglName, RTLD_LOCAL | RTLD_LAZY, app_escapeNs); + } if(dl_handle == NULL) return false; eglGetProcAddress_p = dlsym(dl_handle, "eglGetProcAddress"); if(eglGetProcAddress_p == NULL) { diff --git a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c index 7f3571bac..096f040a9 100644 --- a/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c +++ b/app_pojavlauncher/src/main/jni/ctxbridges/gl_bridge.c @@ -58,6 +58,8 @@ static void gl4esi_get_display_dimensions(int* width, int* height) { gl_render_window_t* gl_init_context(gl_render_window_t *share) { gl_render_window_t* bundle = malloc(sizeof(gl_render_window_t)); memset(bundle, 0, sizeof(gl_render_window_t)); + // Should fix old Angelica wanting no ES bit. It'll still get it in opengles_nothing :p + int glBit = strncmp(getenv("AMETHYST_RENDERER"), "opengles3_desktopgl", 19) ? EGL_OPENGL_ES3_BIT : EGL_OPENGL_BIT; EGLint egl_attributes[] = { EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_DEPTH_SIZE, 24, EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLint num_configs = 0; diff --git a/app_pojavlauncher/src/main/jni/driver_helper/internal_android_dlopen_hook/turnip/hook.c b/app_pojavlauncher/src/main/jni/driver_helper/internal_android_dlopen_hook/turnip/hook.c index c2e085800..a4b0bc768 100644 --- a/app_pojavlauncher/src/main/jni/driver_helper/internal_android_dlopen_hook/turnip/hook.c +++ b/app_pojavlauncher/src/main/jni/driver_helper/internal_android_dlopen_hook/turnip/hook.c @@ -15,7 +15,7 @@ static struct android_namespace_t* turnipNs; static uint64_t (*atrace_get_enabled_tags_p)(); -__attribute__((constructor)) void init_handles() { +__attribute__((constructor)) static void init_handles() { // dlopen manually so the linker dependency is more explicit. // don't want it to do anything funny. void* libandroidnsbypassHandle = dlopen("libandroid_linker_namespace_bypass.so", RTLD_LOCAL | RTLD_LAZY); diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 353ced52b..140fdb5b5 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -160,10 +160,11 @@ int pojavInitOpenGL() { load_vulkan(); setenv("GALLIUM_DRIVER", "zink", 1); setenv("MESA_ANDROID_NO_KMS_SWRAST", "1", 1); - setenv("MESA_LOADER_DRIVER_OVERRIDE", "kgsl", true); + setenv("MESA_DEBUG", "1", 1); + setenv("MESA_LOG_LEVEL", "DEBUG", 1); } else if (!strcmp(renderer, "opengles3_desktopgl_freedreno")) { setenv("GALLIUM_DRIVER", "freedreno", 1); - setenv("MESA_LOADER_DRIVER_OVERRIDE", "kgsl", 1); + setenv("MESA_LOADER_DRIVER_OVERRIDE", "kgsl", true); } set_gl_bridge_tbl(); } else if (strcmp(renderer, "vulkan_zink") == 0) { diff --git a/app_pojavlauncher/src/main/jni/environ/environ.c b/app_pojavlauncher/src/main/jni/environ/environ.c index f75c2eaa9..1adc9ebe8 100644 --- a/app_pojavlauncher/src/main/jni/environ/environ.c +++ b/app_pojavlauncher/src/main/jni/environ/environ.c @@ -7,11 +7,14 @@ #include #include #include "environ.h" +#include "android_linker_namespace_bypass/nsbypass.h" + #define TAG __FILE_NAME__ #include struct pojav_environ_s *pojav_environ; -__attribute__((constructor)) void env_init() { + +__attribute__((constructor)) static void env_init() { char* strptr_env = getenv("POJAV_ENVIRON"); if(strptr_env == NULL) { LOGI("No environ found, creating..."); diff --git a/app_pojavlauncher/src/main/jni/global_state.h b/app_pojavlauncher/src/main/jni/global_state.h new file mode 100644 index 000000000..e61dbebc5 --- /dev/null +++ b/app_pojavlauncher/src/main/jni/global_state.h @@ -0,0 +1,10 @@ +// +// Created by tom on 8/28/26. +// + +#ifndef AMETHYST_GLOBAL_STATE_H +#define AMETHYST_GLOBAL_STATE_H + +extern struct android_namespace_t* app_escapeNs; + +#endif //AMETHYST_GLOBAL_STATE_H diff --git a/app_pojavlauncher/src/main/jni/include/android_linker_namespace_bypass/nsbypass.h b/app_pojavlauncher/src/main/jni/include/android_linker_namespace_bypass/nsbypass.h index f93fe7321..8bde1046a 100644 --- a/app_pojavlauncher/src/main/jni/include/android_linker_namespace_bypass/nsbypass.h +++ b/app_pojavlauncher/src/main/jni/include/android_linker_namespace_bypass/nsbypass.h @@ -2,6 +2,7 @@ // Created by tom on 8/22/26. // +#include #include "platform.h" #include "nsbypass_t.h" @@ -60,5 +61,7 @@ extern struct android_namespace_t* escapeNs; void* linker_ns_dlopen(const char* name, int flag, struct android_namespace_t* ns); void* linker_ns_dlopen_unique(const char* tmpDir, const char* libDir, const char* libName, int flag, struct android_namespace_t* ns); +// Dirs where system libs are stored. +#define SYSTEM_LIBS_PATH "/system/:/system_ext/:/data/:/vendor/:/apex/" #endif //AMETHYST_NSBYPASS_H diff --git a/app_pojavlauncher/src/main/jni/utils.c b/app_pojavlauncher/src/main/jni/utils.c index aaf03e6d6..fd5337921 100644 --- a/app_pojavlauncher/src/main/jni/utils.c +++ b/app_pojavlauncher/src/main/jni/utils.c @@ -5,8 +5,10 @@ #include #include "log.h" - #include "utils.h" +#include "android_linker_namespace_bypass/nsbypass.h" +#include "global_state.h" + typedef int (*Main_Function_t)(int, char**); typedef void (*android_update_LD_LIBRARY_PATH_t)(char*); @@ -125,6 +127,12 @@ JNIEXPORT jboolean JNICALL Java_net_kdt_pojavlaunch_utils_JREUtils_dlopen(JNIEnv void* handle = dlopen(nameUtf, RTLD_GLOBAL | RTLD_LAZY); if (!handle) { LOGE("dlopen %s failed: %s", nameUtf, dlerror()); + // If fail, attempt to use escaped namespace. This gives us access to the symbols while + // still tricking android into loading private API libs :p + + if(!linker_ns_dlopen(nameUtf, RTLD_GLOBAL | RTLD_LAZY, app_escapeNs)){ + LOGE("escaped dlopen %s failed: %s", nameUtf, dlerror()); + } else LOGW("escaped dlopen %s success. are you sure this was supposed to be escaped?", nameUtf); } else { LOGD("dlopen %s success", nameUtf); } diff --git a/app_pojavlauncher/src/main/res/values/headings_array.xml b/app_pojavlauncher/src/main/res/values/headings_array.xml index 94d8b480b..f5918298a 100644 --- a/app_pojavlauncher/src/main/res/values/headings_array.xml +++ b/app_pojavlauncher/src/main/res/values/headings_array.xml @@ -108,5 +108,4 @@ 2 1 - Freedreno (Adreno only, OpenGL 4.6) - (all versions, mid) diff --git a/app_pojavlauncher/src/main/res/values/strings.xml b/app_pojavlauncher/src/main/res/values/strings.xml index 9fb2cf245..b9e98a4b1 100644 --- a/app_pojavlauncher/src/main/res/values/strings.xml +++ b/app_pojavlauncher/src/main/res/values/strings.xml @@ -67,7 +67,9 @@ Renderer Holy GL4ES - (1.21.4< only, fast) Krypton Wrapper - (all versions, fast) - Zink (Vulkan) - (all versions, mid) + Kopper Zink (Vulkan) - (all versions, mid) + Freedreno (Adreno only, OpenGL 4.6) - (all versions, mid) + Zink (Vulkan) - (all versions, slow) SFPEW/MobileGlues (OpenGL ES) - (all versions, fast) LTW (OpenGL ES 3) - 1.17+ only Release @@ -488,7 +490,6 @@ May help with Iris shaderpacks, required for AcceleratedRendering mod AMD FSR 1 Upscaling Auto-renderer select failed, defaulting to HolyGL4ES - Kopper Zink (Vulkan) - (all versions, mid) Sodium detected! It appears you are using sodium, this is unsupported and may lead to graphical issues or crashes. Please remove it and all dependent mods. Delete Sodium and Launch