Skip to content

Commit

Permalink
Feat[renderer]: Add LTW renderer (#6477)
Browse files Browse the repository at this point in the history
* Feat[launcher]: start introducing the Tinywrapper renderer

* Feat[launcher]: add renderer, add compatibility checks

* Chore[ltw]: update to latest

* Style[code]: code cosmetic changes

* Legal[ltw]: make LTW optional

* Fix[ltw]: fix actions, add forgotten file

* Workflow[ltw]: disallow forks, allow building on error
  • Loading branch information
artdeell authored Jan 13, 2025
1 parent ed89b44 commit b28fc4a
Show file tree
Hide file tree
Showing 18 changed files with 140 additions and 485 deletions.
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

0 comments on commit b28fc4a

Please sign in to comment.