Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat[renderer]: Add LTW renderer #6477

Merged
merged 8 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,18 @@ jobs:
distribution: 'temurin'
java-version: '8'

- name: Get LTW
uses: dawidd6/action-download-artifact@v2
continue-on-error: true
with:
github_token: ${{secrets.LTW_CLONER_SECRET}}
repo: PojavLauncherTeam/BigTinyWrapper
workflow: android.yml
workflow_conclusion: success
name: output-aar
path: app_pojavlauncher/libs
allow_forks: false

- name: Get JRE 8
uses: dawidd6/action-download-artifact@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion app_pojavlauncher/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -227,5 +227,5 @@ dependencies {

// implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.0'

implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
}
122 changes: 120 additions & 2 deletions app_pojavlauncher/src/main/java/net/kdt/pojavlaunch/Tools.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.net.Uri;
import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.GLES30;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
Expand Down Expand Up @@ -68,6 +73,7 @@
import net.kdt.pojavlaunch.utils.FileUtils;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.JSONUtils;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import net.kdt.pojavlaunch.utils.OldVersionsUtils;
import net.kdt.pojavlaunch.value.DependentLibrary;
import net.kdt.pojavlaunch.value.MinecraftAccount;
Expand Down Expand Up @@ -178,6 +184,97 @@ public static void initContextConstants(Context ctx){
NATIVE_LIB_DIR = ctx.getApplicationInfo().nativeLibraryDir;
}

/**
* Optimization mods based on Sodium can mitigate the render distance issue. Check if Sodium
* or its derivative is currently installed to skip the render distance check.
* @param gameDir current game directory
* @return whether sodium or a sodium-based mod is installed
*/
private static boolean hasSodium(File gameDir) {
File modsDir = new File(gameDir, "mods");
File[] mods = modsDir.listFiles(file -> file.isFile() && file.getName().endsWith(".jar"));
if(mods == null) return false;
for(File file : mods) {
String name = file.getName();
if(name.contains("sodium") ||
name.contains("embeddium") ||
name.contains("rubidium")) return true;
}
return false;
}

/**
* 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.

* 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;
}

private static boolean checkRenderDistance(File gamedir) {
if(!"opengles3_ltw".equals(Tools.LOCAL_RENDERER)) return false;
if(!affectedByRenderDistanceIssue()) return false;
if(hasSodium(gamedir)) return false;

int renderDistance;
try {
MCOptionUtils.load();
String renderDistanceString = MCOptionUtils.get("renderDistance");
renderDistance = Integer.parseInt(renderDistanceString);
}catch (Exception e) {
Log.e("Tools", "Failed to check render distance", e);
renderDistance = 12; // Assume Minecraft's default render distance
}
// 7 is the render distance "magic number" above which MC creates too many buffers
// for Adreno's OpenGL ES implementation
return renderDistance > 7;
}

public static void launchMinecraft(final AppCompatActivity activity, MinecraftAccount minecraftAccount,
MinecraftProfile minecraftProfile, String versionId, int versionJavaRequirement) throws Throwable {
int freeDeviceMemory = getFreeDeviceMemory(activity);
Expand All @@ -203,10 +300,27 @@ public static void launchMinecraft(final AppCompatActivity activity, MinecraftAc
// to start after the activity is shown again
}
}
Runtime runtime = MultiRTUtils.forceReread(Tools.pickRuntime(minecraftProfile, versionJavaRequirement));
JMinecraftVersionList.Version versionInfo = Tools.getVersionInfo(versionId);
LauncherProfiles.load();
File gamedir = Tools.getGameDirPath(minecraftProfile);
if(checkRenderDistance(gamedir)) {
LifecycleAwareAlertDialog.DialogCreator dialogCreator = ((alertDialog, dialogBuilder) ->
dialogBuilder.setMessage(activity.getString(R.string.ltw_render_distance_warning_msg))
.setPositiveButton(android.R.string.ok, (d, w)->{}));
if(LifecycleAwareAlertDialog.haltOnDialog(activity.getLifecycle(), activity, dialogCreator)) {
return;
}
// If the code goes here, it means that the user clicked "OK". Fix the render distance.
try {
MCOptionUtils.set("renderDistance", "7");
MCOptionUtils.save();
}catch (Exception e) {
Log.e("Tools", "Failed to fix render distance setting", e);
}
}


Runtime runtime = MultiRTUtils.forceReread(Tools.pickRuntime(minecraftProfile, versionJavaRequirement));
JMinecraftVersionList.Version versionInfo = Tools.getVersionInfo(versionId);


// Pre-process specific files
Expand Down Expand Up @@ -1271,12 +1385,16 @@ public static RenderersList getCompatibleRenderers(Context context) {
boolean deviceHasVulkan = checkVulkanSupport(context.getPackageManager());
// Currently, only 32-bit x86 does not have the Zink binary
boolean deviceHasZinkBinary = !(Architecture.is32BitsDevice() && Architecture.isx86Device());
boolean deviceHasOpenGLES3 = JREUtils.getDetectedVersion() >= 3;
// LTW is an optional proprietary dependency
boolean appHasLtw = new File(Tools.NATIVE_LIB_DIR, "libltw.so").exists();
List<String> rendererIds = new ArrayList<>(defaultRenderers.length);
List<String> rendererNames = new ArrayList<>(defaultRendererNames.length);
for(int i = 0; i < defaultRenderers.length; i++) {
String rendererId = defaultRenderers[i];
if(rendererId.contains("vulkan") && !deviceHasVulkan) continue;
if(rendererId.contains("zink") && !deviceHasZinkBinary) continue;
if(rendererId.contains("ltw") && (!deviceHasOpenGLES3 || !appHasLtw)) continue;
rendererIds.add(rendererId);
rendererNames.add(defaultRendererNames[i]);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,9 +220,9 @@ public static void setJavaEnvironment(Activity activity, String jreHome) throws

if(LOCAL_RENDERER != null) {
envMap.put("POJAV_RENDERER", LOCAL_RENDERER);
if(LOCAL_RENDERER.equals("opengles3_desktopgl_angle_vulkan")) {
if(LOCAL_RENDERER.equals("opengles3_ltw")) {
envMap.put("LIBGL_ES", "3");
envMap.put("POJAVEXEC_EGL","libEGL_angle.so"); // Use ANGLE EGL
envMap.put("POJAVEXEC_EGL","libltw.so"); // Use ANGLE EGL
}
}
if(LauncherPreferences.PREF_BIG_CORE_AFFINITY) envMap.put("POJAV_BIG_CORE_AFFINITY", "1");
Expand Down Expand Up @@ -464,7 +464,7 @@ public static String loadGraphicsLibrary(){
case "opengles3":
renderLibrary = "libgl4es_114.so"; break;
case "vulkan_zink": renderLibrary = "libOSMesa.so"; break;
case "opengles3_desktopgl_angle_vulkan" : renderLibrary = "libtinywrapper.so"; break;
case "opengles3_ltw" : renderLibrary = "libltw.so"; break;
default:
Log.w("RENDER_LIBRARY", "No renderer selected, defaulting to opengles2");
renderLibrary = "libgl4es_114.so";
Expand Down
12 changes: 0 additions & 12 deletions app_pojavlauncher/src/main/jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,6 @@ HERE_PATH := $(LOCAL_PATH)

LOCAL_PATH := $(HERE_PATH)

include $(CLEAR_VARS)
LOCAL_MODULE := angle_gles2
LOCAL_SRC_FILES := tinywrapper/angle-gles/$(TARGET_ARCH_ABI)/libGLESv2_angle.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := tinywrapper
LOCAL_SHARED_LIBRARIES := angle_gles2
LOCAL_SRC_FILES := tinywrapper/main.c tinywrapper/string_utils.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/tinywrapper
include $(BUILD_SHARED_LIBRARY)

$(call import-module,prefab/bytehook)
LOCAL_PATH := $(HERE_PATH)

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading