diff --git a/.gitignore b/.gitignore index 235cf03e66..9fb5d26a8a 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ local.properties app_pojavlauncher/.cxx/ .vs/ /curseforge_key.txt +/app_pojavlauncher/libs/ltw-release.aar diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java index 0167492123..dc2fb2340e 100644 --- a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java @@ -70,6 +70,7 @@ import net.kdt.pojavlaunch.utils.DateUtils; import net.kdt.pojavlaunch.utils.DownloadUtils; import net.kdt.pojavlaunch.utils.FileUtils; +import net.kdt.pojavlaunch.utils.GLInfoUtils; import net.kdt.pojavlaunch.utils.JREUtils; import net.kdt.pojavlaunch.utils.JSONUtils; import net.kdt.pojavlaunch.utils.MCOptionUtils; @@ -233,8 +234,7 @@ private static boolean hasSodium(File gameDir) { * Initialize OpenGL and do checks to see if the GPU of the device is affected by the render * distance issue. - * Currently only checks whether the user has an Adreno GPU capable of OpenGL ES 3 - * and surfaceless rendering installed. + * Currently only checks whether the user has an Adreno GPU capable of OpenGL ES 3. * This issue is caused by a very severe limit on the amount of GL buffer names that could be allocated * by the Adreno properietary GLES driver. @@ -242,44 +242,8 @@ private static boolean hasSodium(File gameDir) { * @return whether the GPU is affected by the Large Thin Wrapper render distance issue on vanilla */ private static boolean affectedByRenderDistanceIssue() { - EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); - if(eglDisplay == EGL14.EGL_NO_DISPLAY || !EGL14.eglInitialize(eglDisplay, null, 0, null, 0)) return false; - int[] egl_attributes = new int[] { - EGL14.EGL_BLUE_SIZE, 8, - EGL14.EGL_GREEN_SIZE, 8, - EGL14.EGL_RED_SIZE, 8, - EGL14.EGL_ALPHA_SIZE, 8, - EGL14.EGL_DEPTH_SIZE, 24, - EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT, - EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, - EGL14.EGL_NONE - }; - EGLConfig[] config = new EGLConfig[1]; - int[] num_configs = new int[]{0}; - if(!EGL14.eglChooseConfig(eglDisplay, egl_attributes, 0, config, 0, 1, num_configs, 0) || num_configs[0] == 0) { - EGL14.eglTerminate(eglDisplay); - Log.e("CheckVendor", "Failed to choose an EGL config"); - return false; - } - int[] egl_context_attributes = new int[] { EGL14.EGL_CONTEXT_CLIENT_VERSION, 3, EGL14.EGL_NONE }; - EGLContext context = EGL14.eglCreateContext(eglDisplay, config[0], EGL14.EGL_NO_CONTEXT, egl_context_attributes, 0); - if(context == EGL14.EGL_NO_CONTEXT) { - Log.e("CheckVendor", "Failed to create a context"); - EGL14.eglTerminate(eglDisplay); - return false; - } - if(!EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, context)) { - Log.e("CheckVendor", "Failed to make context current"); - EGL14.eglDestroyContext(eglDisplay, context); - EGL14.eglTerminate(eglDisplay); - } - boolean is_adreno = GLES30.glGetString(GLES30.GL_VENDOR).equals("Qualcomm") && - GLES30.glGetString(GLES30.GL_RENDERER).contains("Adreno"); - Log.e("CheckVendor", "Running Adreno graphics: "+is_adreno); - EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); - EGL14.eglDestroyContext(eglDisplay, context); - EGL14.eglTerminate(eglDisplay); - return is_adreno; + GLInfoUtils.GLInfo info = GLInfoUtils.getInfo(); + return info.renderer.contains("Adreno") && info.vendor.equals("Qualcomm") && info.glesMajorVersion >= 3; } private static boolean checkRenderDistance(File gamedir) { @@ -1071,6 +1035,8 @@ public static void printLauncherInfo(String gameVersion, String javaArguments) { Logger.appendToLog("Info: API version: " + SDK_INT); Logger.appendToLog("Info: Selected Minecraft version: " + gameVersion); Logger.appendToLog("Info: Custom Java arguments: \"" + javaArguments + "\""); + GLInfoUtils.GLInfo info = GLInfoUtils.getInfo(); + Logger.appendToLog("Info: Graphics device: "+info.vendor+ " "+info.renderer+" (OpenGL ES "+info.glesMajorVersion+")"); } public interface DownloaderFeedback { diff --git a/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java new file mode 100644 index 0000000000..32a350b31d --- /dev/null +++ b/app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/utils/GLInfoUtils.java @@ -0,0 +1,125 @@ +package net.kdt.pojavlaunch.utils; + +import android.opengl.EGL14; +import android.opengl.EGLConfig; +import android.opengl.EGLContext; +import android.opengl.EGLDisplay; +import android.opengl.GLES20; +import android.opengl.GLES30; +import android.util.Log; + +public class GLInfoUtils { + public static String GLES_VERSION_PREFIX = "OpenGL ES "; + private static GLInfo info; + + private static int getMajorGLVersion(String versionString) { + if(versionString.startsWith(GLES_VERSION_PREFIX)) { + versionString = versionString.substring(GLES_VERSION_PREFIX.length()); + } + int firstDot = versionString.indexOf('.'); + String majorVersion = versionString.substring(0, firstDot).trim(); + return Integer.parseInt(majorVersion); + } + + private static GLInfo queryInfo(int contextGLVersion) { + String vendor = GLES20.glGetString(GLES20.GL_VENDOR); + String renderer = GLES20.glGetString(GLES20.GL_RENDERER); + String versionString = GLES20.glGetString(GLES30.GL_VERSION); + int version = 2; + try { + version = getMajorGLVersion(versionString); + }catch (NumberFormatException e) { + Log.w("GLInfoUtils","Failed to parse GL version number, falling back to 2", e); + } + // LTW depends on the ability to create a context with a major version of 3, + // and even if the string parse returns 3 while EGL can only create 2, + // it's still a noncompilant implementation + version = Math.min(version, contextGLVersion); + return new GLInfo(vendor, renderer, version); + } + + private static void initDummyInfo() { + Log.e("GLInfoUtils", "An error happened during info query. Will use dummy info. This should be investigated."); + info = new GLInfo("", "", 2); + } + + private static EGLContext tryCreateContext(EGLDisplay eglDisplay, EGLConfig config, int majorVersion) { + int[] egl_context_attributes = new int[] { EGL14.EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL14.EGL_NONE }; + EGLContext context = EGL14.eglCreateContext(eglDisplay, config, EGL14.EGL_NO_CONTEXT, egl_context_attributes, 0); + if(context == EGL14.EGL_NO_CONTEXT) { + Log.e("GLInfoUtils", "Failed to create a context with major version "+majorVersion); + return null; + } + return context; + } + + private static boolean initAndQueryInfo() { + // This is here just to satisfy Android M which incorrectly null-checks it + int[] egl_version = new int[2]; + EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); + if(eglDisplay == EGL14.EGL_NO_DISPLAY || !EGL14.eglInitialize(eglDisplay, egl_version, 0 , egl_version, 1)) return false; + int[] egl_attributes = new int[] { + EGL14.EGL_BLUE_SIZE, 8, + EGL14.EGL_GREEN_SIZE, 8, + EGL14.EGL_RED_SIZE, 8, + EGL14.EGL_ALPHA_SIZE, 8, + EGL14.EGL_DEPTH_SIZE, 24, + EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT|EGL14.EGL_WINDOW_BIT, + EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, + EGL14.EGL_NONE + }; + EGLConfig[] config = new EGLConfig[1]; + int[] num_configs = new int[]{0}; + if(!EGL14.eglChooseConfig(eglDisplay, egl_attributes, 0, config, 0, 1, num_configs, 0) || num_configs[0] == 0) { + EGL14.eglTerminate(eglDisplay); + Log.e("GLInfoUtils", "Failed to choose an EGL config"); + return false; + } + + int contextGLVersion = 3; + + EGLContext context; + context = tryCreateContext(eglDisplay, config[0], 3); + if(context == null) { + contextGLVersion = 2; + context = tryCreateContext(eglDisplay, config[0], 2); + } + + if(!EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, context)) { + Log.e("GLInfoUtils", "Failed to make context current"); + EGL14.eglDestroyContext(eglDisplay, context); + EGL14.eglTerminate(eglDisplay); + } + + info = queryInfo(contextGLVersion); + + EGL14.eglMakeCurrent(eglDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); + EGL14.eglDestroyContext(eglDisplay, context); + EGL14.eglTerminate(eglDisplay); + return true; + } + + public static GLInfo getInfo() { + if(info != null) return info; + Log.i("GLInfoUtils", "Querying graphics device info..."); + boolean infoQueryResult = false; + try { + infoQueryResult = initAndQueryInfo(); + }catch (Throwable e) { + Log.e("GLInfoUtils", "Throwable when trying to initialize GL info", e); + } + if(!infoQueryResult) initDummyInfo(); + return info; + } + + public static class GLInfo { + public final String vendor; + public final String renderer; + public final int glesMajorVersion; + protected GLInfo(String vendor, String renderer, int glesMajorVersion) { + this.vendor = vendor; + this.renderer = renderer; + this.glesMajorVersion = glesMajorVersion; + } + } +} 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 faf2c34d6e..ebb8a8a9d4 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 @@ -240,8 +240,10 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws } reader.close(); } + + GLInfoUtils.GLInfo info = GLInfoUtils.getInfo(); if(!envMap.containsKey("LIBGL_ES") && LOCAL_RENDERER != null) { - int glesMajor = getDetectedVersion(); + int glesMajor = info.glesMajorVersion; Log.i("glesDetect","GLES version detected: "+glesMajor); if (glesMajor < 3) { @@ -255,6 +257,11 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws envMap.put("LIBGL_ES", "3"); } } + + if(info.vendor.equals("Qualcomm") && info.renderer.contains("Adreno")) { + envMap.put("POJAV_LOAD_TURNIP", "1"); + } + for (Map.Entry env : envMap.entrySet()) { Logger.appendToLog("Added custom env: " + env.getKey() + "=" + env.getValue()); try { @@ -512,61 +519,7 @@ private static boolean hasExtension(String extensions, String name) { } public static int getDetectedVersion() { - /* - * Get all the device configurations and check the EGL_RENDERABLE_TYPE attribute - * to determine the highest ES version supported by any config. The - * EGL_KHR_create_context extension is required to check for ES3 support; if the - * extension is not present this test will fail to detect ES3 support. This - * effectively makes the extension mandatory for ES3-capable devices. - */ - EGL10 egl = (EGL10) EGLContext.getEGL(); - EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); - int[] numConfigs = new int[1]; - if (egl.eglInitialize(display, null)) { - try { - boolean checkES3 = hasExtension(egl.eglQueryString(display, EGL10.EGL_EXTENSIONS), - "EGL_KHR_create_context"); - if (egl.eglGetConfigs(display, null, 0, numConfigs)) { - EGLConfig[] configs = new EGLConfig[numConfigs[0]]; - if (egl.eglGetConfigs(display, configs, numConfigs[0], numConfigs)) { - int highestEsVersion = 0; - int[] value = new int[1]; - for (int i = 0; i < numConfigs[0]; i++) { - if (egl.eglGetConfigAttrib(display, configs[i], - EGL10.EGL_RENDERABLE_TYPE, value)) { - if (checkES3 && ((value[0] & EGL_OPENGL_ES3_BIT_KHR) == - EGL_OPENGL_ES3_BIT_KHR)) { - if (highestEsVersion < 3) highestEsVersion = 3; - } else if ((value[0] & EGL_OPENGL_ES2_BIT) == EGL_OPENGL_ES2_BIT) { - if (highestEsVersion < 2) highestEsVersion = 2; - } else if ((value[0] & EGL_OPENGL_ES_BIT) == EGL_OPENGL_ES_BIT) { - if (highestEsVersion < 1) highestEsVersion = 1; - } - } else { - Log.w("glesDetect", "Getting config attribute with " - + "EGL10#eglGetConfigAttrib failed " - + "(" + i + "/" + numConfigs[0] + "): " - + egl.eglGetError()); - } - } - return highestEsVersion; - } else { - Log.e("glesDetect", "Getting configs with EGL10#eglGetConfigs failed: " - + egl.eglGetError()); - return -1; - } - } else { - Log.e("glesDetect", "Getting number of configs with EGL10#eglGetConfigs failed: " - + egl.eglGetError()); - return -2; - } - } finally { - egl.eglTerminate(display); - } - } else { - Log.e("glesDetect", "Couldn't initialize EGL."); - return -3; - } + return GLInfoUtils.getInfo().glesMajorVersion; } public static native int chdir(String path); public static native boolean dlopen(String libPath); diff --git a/app_pojavlauncher/src/main/jni/Android.mk b/app_pojavlauncher/src/main/jni/Android.mk index 6619cd41ea..24ad2e474f 100644 --- a/app_pojavlauncher/src/main/jni/Android.mk +++ b/app_pojavlauncher/src/main/jni/Android.mk @@ -38,7 +38,6 @@ LOCAL_SRC_FILES := \ ifeq ($(TARGET_ARCH_ABI),arm64-v8a) LOCAL_CFLAGS += -DADRENO_POSSIBLE -LOCAL_LDLIBS += -lEGL -lGLESv2 endif include $(BUILD_SHARED_LIBRARY) diff --git a/app_pojavlauncher/src/main/jni/egl_bridge.c b/app_pojavlauncher/src/main/jni/egl_bridge.c index 1b37f6bdbb..80908d4051 100644 --- a/app_pojavlauncher/src/main/jni/egl_bridge.c +++ b/app_pojavlauncher/src/main/jni/egl_bridge.c @@ -99,41 +99,8 @@ EXTERNAL_API void* pojavGetCurrentContext() { //#define ADRENO_POSSIBLE #ifdef ADRENO_POSSIBLE -//Checks if your graphics are Adreno. Returns true if your graphics are Adreno, false otherwise or if there was an error -bool checkAdrenoGraphics() { - EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); - if(eglDisplay == EGL_NO_DISPLAY || eglInitialize(eglDisplay, NULL, NULL) != EGL_TRUE) return false; - 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_PBUFFER_BIT, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; - EGLint num_configs = 0; - if(eglChooseConfig(eglDisplay, egl_attributes, NULL, 0, &num_configs) != EGL_TRUE || num_configs == 0) { - eglTerminate(eglDisplay); - return false; - } - EGLConfig eglConfig; - eglChooseConfig(eglDisplay, egl_attributes, &eglConfig, 1, &num_configs); - const EGLint egl_context_attributes[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; - EGLContext context = eglCreateContext(eglDisplay, eglConfig, EGL_NO_CONTEXT, egl_context_attributes); - if(context == EGL_NO_CONTEXT) { - eglTerminate(eglDisplay); - return false; - } - if(eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, context) != EGL_TRUE) { - eglDestroyContext(eglDisplay, context); - eglTerminate(eglDisplay); - } - const char* vendor = glGetString(GL_VENDOR); - const char* renderer = glGetString(GL_RENDERER); - bool is_adreno = false; - if(strcmp(vendor, "Qualcomm") == 0 && strstr(renderer, "Adreno") != NULL) { - is_adreno = true; // TODO: check for Turnip support - } - eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(eglDisplay, context); - eglTerminate(eglDisplay); - return is_adreno; -} void* load_turnip_vulkan() { - if(!checkAdrenoGraphics()) return NULL; + if(getenv("POJAV_LOAD_TURNIP") == NULL) return NULL; const char* native_dir = getenv("POJAV_NATIVEDIR"); const char* cache_dir = getenv("TMPDIR"); if(!linker_ns_load(native_dir)) return NULL;