Skip to content

Commit

Permalink
Feat[launcher]: remove duplicate GLES initializations
Browse files Browse the repository at this point in the history
  • Loading branch information
artdeell committed Jan 20, 2025
1 parent 60ac793 commit dc0d1ba
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 131 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ local.properties
app_pojavlauncher/.cxx/
.vs/
/curseforge_key.txt
/app_pojavlauncher/libs/ltw-release.aar
46 changes: 6 additions & 40 deletions app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -233,53 +234,16 @@ 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.
* @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) {
Expand Down Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -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("<Unknown>", "<Unknown>", 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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<String, String> env : envMap.entrySet()) {
Logger.appendToLog("Added custom env: " + env.getKey() + "=" + env.getValue());
try {
Expand Down Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
35 changes: 1 addition & 34 deletions app_pojavlauncher/src/main/jni/egl_bridge.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit dc0d1ba

Please sign in to comment.