From 9621c605c9ef95647fdde59bdeb7b48d6d8d81a1 Mon Sep 17 00:00:00 2001 From: Utkarsh Dalal Date: Sun, 30 Aug 2026 13:51:31 +0530 Subject: [PATCH 1/2] Made faster external loading optional and disabled by default as it was causing bugs, added experimental option to disable libredirect to improve performance --- .../ui/component/dialog/GeneralTab.kt | 21 ++++++++++++++ .../ui/screen/xserver/XServerScreen.kt | 16 ++++++----- .../app/gamenative/utils/ContainerUtils.kt | 4 +++ .../com/winlator/container/Container.java | 26 ++++++++++++++++++ .../com/winlator/container/ContainerData.kt | 6 ++++ .../xenvironment/ImageFsInstaller.java | 5 ++++ .../BionicProgramLauncherComponent.java | 22 ++++++++++++--- app/src/main/res/values-da/strings.xml | 4 +++ app/src/main/res/values-de/strings.xml | 4 +++ app/src/main/res/values-es/strings.xml | 4 +++ app/src/main/res/values-fr/strings.xml | 4 +++ app/src/main/res/values-it/strings.xml | 4 +++ app/src/main/res/values-ja/strings.xml | 4 +++ app/src/main/res/values-ko/strings.xml | 4 +++ app/src/main/res/values-pl/strings.xml | 4 +++ app/src/main/res/values-pt-rBR/strings.xml | 4 +++ app/src/main/res/values-ro/strings.xml | 4 +++ app/src/main/res/values-ru/strings.xml | 4 +++ app/src/main/res/values-uk/strings.xml | 4 +++ app/src/main/res/values-zh-rCN/strings.xml | 4 +++ app/src/main/res/values-zh-rTW/strings.xml | 4 +++ app/src/main/res/values/strings.xml | 4 +++ .../assets/libredirect-bionic-wx-minimal.so | Bin 0 -> 38952 bytes 23 files changed, 149 insertions(+), 11 deletions(-) create mode 100755 app/src/modern/assets/libredirect-bionic-wx-minimal.so diff --git a/app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt b/app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt index 66653ed568..78cb84231f 100644 --- a/app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt +++ b/app/src/main/java/app/gamenative/ui/component/dialog/GeneralTab.kt @@ -396,7 +396,28 @@ fun GeneralTabContent( } }, ) + SettingsSwitch( + colors = settingsTileColorsAlt(), + title = { Text(text = stringResource(R.string.disable_libredirect_title)) }, + subtitle = { Text(text = stringResource(R.string.disable_libredirect_subtitle)) }, + state = config.disableLibredirect, + onCheckedChange = { + state.config.value = if (it) { + config.copy(disableLibredirect = true, fasterExternalLoading = false) + } else { + config.copy(disableLibredirect = false) + } + }, + ) } + SettingsSwitch( + colors = settingsTileColorsAlt(), + enabled = !config.disableLibredirect, + title = { Text(text = stringResource(R.string.faster_external_loading_title)) }, + subtitle = { Text(text = stringResource(R.string.faster_external_loading_subtitle)) }, + state = config.fasterExternalLoading, + onCheckedChange = { state.config.value = config.copy(fasterExternalLoading = it) }, + ) val steamTypeItems = listOf("Normal", "Light", "Ultra Light") val currentSteamTypeIndex = when (config.steamType.lowercase()) { Container.STEAM_TYPE_LIGHT -> 1 diff --git a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt index d7af2046fb..8a7992f3ab 100644 --- a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt +++ b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt @@ -3921,13 +3921,15 @@ private fun setupXEnvironment( envVars.remove("VKD3D_FRAME_RATE") if (!envVars.has("WINEESYNC")) envVars.put("WINEESYNC", "1") - val ffpGameDir = runCatching { - Container.drivesIterator(container.drives).asSequence() - .firstOrNull { it[0] == "A" }?.let { File(it[1]).canonicalFile.path } - }.getOrNull() ?: "" - if (ffpGameDir.startsWith("/storage/") && !ffpGameDir.startsWith("/storage/emulated/")) { - envVars.put("FFP_ENABLE", "1") - envVars.put("FFP_MARKERS", "/steamapps/common/;/dosdevices/a:") + if (container.isFasterExternalLoading) { + val ffpGameDir = runCatching { + Container.drivesIterator(container.drives).asSequence() + .firstOrNull { it[0] == "A" }?.let { File(it[1]).canonicalFile.path } + }.getOrNull() ?: "" + if (ffpGameDir.startsWith("/storage/") && !ffpGameDir.startsWith("/storage/emulated/")) { + envVars.put("FFP_ENABLE", "1") + envVars.put("FFP_MARKERS", "/steamapps/common/;/dosdevices/a:") + } } val graphicsDriverConfig = KeyValueSet(container.getGraphicsDriverConfig()) diff --git a/app/src/main/java/app/gamenative/utils/ContainerUtils.kt b/app/src/main/java/app/gamenative/utils/ContainerUtils.kt index 791774c0d8..3c7fbd5b71 100644 --- a/app/src/main/java/app/gamenative/utils/ContainerUtils.kt +++ b/app/src/main/java/app/gamenative/utils/ContainerUtils.kt @@ -335,6 +335,8 @@ object ContainerUtils { fexcorePreset = container.getFEXCorePreset(), language = container.language, sdlControllerAPI = container.isSdlControllerAPI, + fasterExternalLoading = container.isFasterExternalLoading, + disableLibredirect = container.isDisableLibredirect, useSteamInput = useSteamInput, forceDlc = container.isForceDlc, localSavesOnly = container.isLocalSavesOnly, @@ -520,6 +522,8 @@ object ContainerUtils { container.box86Preset = containerData.box86Preset container.box64Preset = containerData.box64Preset container.isSdlControllerAPI = containerData.sdlControllerAPI + container.isFasterExternalLoading = containerData.fasterExternalLoading + container.isDisableLibredirect = containerData.disableLibredirect container.putExtra("useSteamInput", containerData.useSteamInput) container.desktopTheme = containerData.desktopTheme container.graphicsDriverVersion = containerData.graphicsDriverVersion diff --git a/app/src/main/java/com/winlator/container/Container.java b/app/src/main/java/com/winlator/container/Container.java index b2be549991..accd82e1e5 100644 --- a/app/src/main/java/com/winlator/container/Container.java +++ b/app/src/main/java/com/winlator/container/Container.java @@ -126,6 +126,8 @@ public enum XrControllerMapping { private String execArgs = ""; // Default exec arguments private String executablePath = ""; // Executable path for container private boolean sdlControllerAPI; + private boolean fasterExternalLoading; + private boolean disableLibredirect; // Preferred game language for Goldberg force_language.txt private String language = "english"; @@ -396,6 +398,22 @@ public void setSdlControllerAPI(boolean sdlControllerAPI) { this.sdlControllerAPI = sdlControllerAPI; } + public boolean isFasterExternalLoading() { + return fasterExternalLoading; + } + + public void setFasterExternalLoading(boolean fasterExternalLoading) { + this.fasterExternalLoading = fasterExternalLoading; + } + + public boolean isDisableLibredirect() { + return disableLibredirect; + } + + public void setDisableLibredirect(boolean disableLibredirect) { + this.disableLibredirect = disableLibredirect; + } + public String getLanguage() { return language != null ? language : "english"; } @@ -736,6 +754,8 @@ public void saveData() { data.put("executablePath", executablePath); data.put("needsUnpacking", needsUnpacking); data.put("sdlControllerAPI", sdlControllerAPI); + data.put("fasterExternalLoading", fasterExternalLoading); + data.put("disableLibredirect", disableLibredirect); // Disable mouse input flag data.put("disableMouseInput", disableMouseInput); // Touchscreen mode flag @@ -953,6 +973,12 @@ public void loadData(JSONObject data) throws JSONException { case "sdlControllerAPI" : setSdlControllerAPI(data.getBoolean(key)); break; + case "fasterExternalLoading" : + setFasterExternalLoading(data.getBoolean(key)); + break; + case "disableLibredirect" : + setDisableLibredirect(data.getBoolean(key)); + break; case "disableMouseInput" : setDisableMouseInput(data.getBoolean(key)); break; diff --git a/app/src/main/java/com/winlator/container/ContainerData.kt b/app/src/main/java/com/winlator/container/ContainerData.kt index 11093b1ec1..b4775bb29c 100644 --- a/app/src/main/java/com/winlator/container/ContainerData.kt +++ b/app/src/main/java/com/winlator/container/ContainerData.kt @@ -70,6 +70,8 @@ data class ContainerData( val shaderBackend: String = "glsl", val useGLSL: String = "enabled", val sdlControllerAPI: Boolean = true, + val fasterExternalLoading: Boolean = false, + val disableLibredirect: Boolean = false, /** Enable Steam Input **/ val useSteamInput: Boolean = false, /** Enable XInput API **/ @@ -155,6 +157,8 @@ data class ContainerData( "fexcoreMultiBlock" to state.fexcoreMultiBlock, "fexcorePreset" to state.fexcorePreset, "sdlControllerAPI" to state.sdlControllerAPI, + "fasterExternalLoading" to state.fasterExternalLoading, + "disableLibredirect" to state.disableLibredirect, "useSteamInput" to state.useSteamInput, "enableXInput" to state.enableXInput, "enableDInput" to state.enableDInput, @@ -226,6 +230,8 @@ data class ContainerData( fexcoreMultiBlock = (savedMap["fexcoreMultiBlock"] as? String) ?: "Disabled", fexcorePreset = (savedMap["fexcorePreset"] as? String) ?: FEXCorePreset.INTERMEDIATE, sdlControllerAPI = savedMap["sdlControllerAPI"] as Boolean, + fasterExternalLoading = (savedMap["fasterExternalLoading"] as? Boolean) ?: false, + disableLibredirect = (savedMap["disableLibredirect"] as? Boolean) ?: false, useSteamInput = (savedMap["useSteamInput"] as? Boolean) ?: false, enableXInput = savedMap["enableXInput"] as Boolean, enableDInput = savedMap["enableDInput"] as Boolean, diff --git a/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java b/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java index 996d769263..a9ef65cb0c 100644 --- a/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java +++ b/app/src/main/java/com/winlator/xenvironment/ImageFsInstaller.java @@ -97,6 +97,11 @@ private static void ensureBionicLib(Context context, File imagefs) { FileUtils.copy(context, "libredirect-bionic-wx.so", wxDest); chmod(wxDest); } + File wxMinimalDest = new File(imagefs, "usr/lib/libredirect-bionic-wx-minimal.so"); + if (!wxMinimalDest.exists()) { + FileUtils.copy(context, "libredirect-bionic-wx-minimal.so", wxMinimalDest); + chmod(wxMinimalDest); + } } } diff --git a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java index c8a2065dee..acb219cb06 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java @@ -82,6 +82,20 @@ public WineInfo getWineInfo() { public Container getContainer() { return this.container; } public void setContainer(Container container) { this.container = container; } + // Resolve which libredirect shim to preload. Normally the flavor default + // (PRELOAD_BIONIC_SO). When the container disables libredirect, modern falls + // back to the W^X-only minimal shim (still required to run Wine on a strict + // W^X kernel) and legacy preloads nothing. Returns null to preload nothing. + private String resolveLibredirectPreload(ImageFs imageFs) { + if (container != null && container.isDisableLibredirect()) { + if (BuildConfig.MODERN_ANDROID) { + return imageFs.getLibDir() + "/libredirect-bionic-wx-minimal.so"; + } + return null; + } + return imageFs.getLibDir() + "/" + BuildConfig.PRELOAD_BIONIC_SO; + } + /** Numeric Steam appid for the game in this container (e.g. "221380"). * Set from XServerScreen before start(); only consumed in real-Steam mode * to publish SteamGameId / SteamAppId for the steam_helper handshake. */ @@ -301,13 +315,13 @@ private int execGuestProgram() { String ld_preload = ""; String sysvPath = imageFs.getLibDir() + "/libandroid-sysvshm.so"; String evshimPath = context.getApplicationInfo().nativeLibraryDir + "/libevshim.so"; - String replacePath = imageFs.getLibDir() + "/" + BuildConfig.PRELOAD_BIONIC_SO; + String replacePath = resolveLibredirectPreload(imageFs); if (new File(sysvPath).exists()) ld_preload += sysvPath; ld_preload += ":" + evshimPath; - ld_preload += ":" + replacePath; + if (replacePath != null) ld_preload += ":" + replacePath; envVars.put("LD_PRELOAD", ld_preload); envVars.put("EVSHIM_WINE", 1); @@ -672,11 +686,11 @@ public String execShellCommand(String command, boolean includeStderr) { String ld_preload = ""; String sysvPath = imageFs.getLibDir() + "/libandroid-sysvshm.so"; - String replacePath = imageFs.getLibDir() + "/" + BuildConfig.PRELOAD_BIONIC_SO; + String replacePath = resolveLibredirectPreload(imageFs); if (new File(sysvPath).exists()) ld_preload += sysvPath; - ld_preload += ":" + replacePath; + if (replacePath != null) ld_preload += ":" + replacePath; envVars.put("LD_PRELOAD", ld_preload); diff --git a/app/src/main/res/values-da/strings.xml b/app/src/main/res/values-da/strings.xml index 53a4e123a8..561012c6b2 100644 --- a/app/src/main/res/values-da/strings.xml +++ b/app/src/main/res/values-da/strings.xml @@ -2232,4 +2232,8 @@ Føjet til favoritter Føjede %1$s til favoritter VR-opdateringsfrekvens + Hurtigere indlæsning fra eksternt lager + Kan gøre spilstart fra eksternt lager markant hurtigere, men kan give problemer i nogle spil + Deaktiver libredirect + Kan forbedre ydeevnen, men kan også give uventede problemer diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d7f661002e..c86ecbd051 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -2302,4 +2302,8 @@ Zu Favoriten hinzugefügt %1$s zu Favoriten hinzugefügt VR-Bildwiederholrate + Schnelleres Laden von externem Speicher + Kann den Spielstart von externem Speicher deutlich beschleunigen, kann aber bei manchen Spielen Probleme verursachen + libredirect deaktivieren + Kann die Leistung verbessern, aber auch unerwartete Probleme verursachen diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 82dde47ce2..e7366db0a8 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -2360,4 +2360,8 @@ Añadido a favoritos %1$s añadido a favoritos Frecuencia de actualización de RV + Carga más rápida desde almacenamiento externo + Puede acelerar considerablemente el inicio de juegos desde almacenamiento externo, pero puede causar problemas en algunos juegos + Desactivar libredirect + Puede mejorar el rendimiento, pero también puede causar problemas inesperados diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 928934755d..36e2cefdb2 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -2362,4 +2362,8 @@ Ajouté aux favoris %1$s ajouté aux favoris Taux de rafraîchissement VR + Chargement plus rapide depuis le stockage externe + Peut accélérer considérablement le démarrage des jeux depuis le stockage externe, mais peut causer des problèmes dans certains jeux + Désactiver libredirect + Peut améliorer les performances, mais peut aussi causer des problèmes inattendus diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 1675941165..18772c48f4 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -2353,4 +2353,8 @@ Aggiunto ai preferiti %1$s aggiunto ai preferiti Frequenza di aggiornamento VR + Caricamento più veloce dalla memoria esterna + Può velocizzare notevolmente l\'avvio dei giochi dalla memoria esterna, ma può causare problemi in alcuni giochi + Disattiva libredirect + Può migliorare le prestazioni, ma può anche causare problemi imprevisti diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index b8d6f6dab9..9e42f29549 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -2316,4 +2316,8 @@ お気に入りに追加しました %1$s をお気に入りに追加しました VRリフレッシュレート + 外部ストレージからの高速読み込み + 外部ストレージからのゲーム起動を大幅に高速化できますが、一部のゲームで問題が発生する可能性があります + libredirect を無効にする + パフォーマンスが向上する場合がありますが、予期しない問題が発生する可能性もあります diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index bd259d8e18..b7e262bae0 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -2357,4 +2357,8 @@ 즐겨찾기에 추가됨 %1$s을(를) 즐겨찾기에 추가함 VR 재생 빈도 + 외부 저장소에서 더 빠른 로딩 + 외부 저장소에서의 게임 부팅 속도를 크게 높일 수 있지만 일부 게임에서 문제가 발생할 수 있습니다 + libredirect 비활성화 + 성능이 향상될 수 있지만 예기치 않은 문제가 발생할 수도 있습니다 diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 131fe34821..ebd6c57cb6 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -2366,4 +2366,8 @@ Dodano do ulubionych Dodano %1$s do ulubionych Częstotliwość odświeżania VR + Szybsze wczytywanie z pamięci zewnętrznej + Może znacznie przyspieszyć uruchamianie gier z pamięci zewnętrznej, ale może powodować problemy w niektórych grach + Wyłącz libredirect + Może poprawić wydajność, ale może też powodować nieoczekiwane problemy diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 94708d1101..0ccb209480 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -2232,4 +2232,8 @@ Adicionado aos favoritos %1$s adicionado aos favoritos Taxa de atualização de VR + Carregamento mais rápido do armazenamento externo + Pode acelerar bastante a inicialização de jogos no armazenamento externo, mas pode causar problemas em alguns jogos + Desativar libredirect + Pode melhorar o desempenho, mas também pode causar problemas inesperados diff --git a/app/src/main/res/values-ro/strings.xml b/app/src/main/res/values-ro/strings.xml index 2987833fa3..be8ac908ae 100644 --- a/app/src/main/res/values-ro/strings.xml +++ b/app/src/main/res/values-ro/strings.xml @@ -2366,4 +2366,8 @@ Adăugat la favorite %1$s adăugat la favorite Rată de reîmprospătare VR + Încărcare mai rapidă de pe stocarea externă + Poate accelera semnificativ pornirea jocurilor de pe stocarea externă, dar poate cauza probleme în unele jocuri + Dezactivează libredirect + Poate îmbunătăți performanța, dar poate cauza și probleme neașteptate diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 69b69abd4d..bc4ad17d80 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -2294,4 +2294,8 @@ https://gamenative.app Добавлено в избранное %1$s добавлено в избранное Частота обновления VR + Быстрая загрузка с внешнего накопителя + Может значительно ускорить запуск игр с внешнего накопителя, но может вызывать проблемы в некоторых играх + Отключить libredirect + Может повысить производительность, но также может вызвать непредвиденные проблемы diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 7f009af0b5..8b741045a4 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -2362,4 +2362,8 @@ Додано до вибраного %1$s додано до вибраного Частота оновлення VR + Швидше завантаження із зовнішнього накопичувача + Може значно пришвидшити запуск ігор із зовнішнього накопичувача, але може спричиняти проблеми в деяких іграх + Вимкнути libredirect + Може підвищити продуктивність, але також може спричинити неочікувані проблеми diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 710e7dd7fa..e6b1fef5f5 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -2377,4 +2377,8 @@ 已添加到收藏 已将 %1$s 添加到收藏 VR 刷新率 + 从外部存储更快加载 + 可显著加快从外部存储启动游戏的速度,但可能导致部分游戏出现问题 + 禁用 libredirect + 可能提升性能,但也可能导致意外问题 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 9243ca7656..d59f3582e2 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -2368,4 +2368,8 @@ 已加入收藏 已將 %1$s 加入收藏 VR 重新整理頻率 + 從外部儲存空間更快載入 + 可顯著加快從外部儲存空間啟動遊戲的速度,但可能導致部分遊戲出現問題 + 停用 libredirect + 可能提升效能,但也可能導致意外問題 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dead7a0b3c..286cbe7248 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -224,6 +224,10 @@ Open File Download File Processor Affinity + Faster loading from external storage + Can significantly speed up game boot from external storage, but may cause issues in some games + Disable libredirect + May improve performance but may also cause unexpected issues Bring to Front End Process New File diff --git a/app/src/modern/assets/libredirect-bionic-wx-minimal.so b/app/src/modern/assets/libredirect-bionic-wx-minimal.so new file mode 100755 index 0000000000000000000000000000000000000000..530da42f0cbf1e3b336159f3ebb21c1f10d06534 GIT binary patch literal 38952 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 z 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 NiVN6hF@BQs{~s%z9UA}u literal 0 HcmV?d00001 From dd27f5b2b94d8550bdd881b82c8d7fab18d5203f Mon Sep 17 00:00:00 2001 From: Utkarsh Dalal Date: Sun, 30 Aug 2026 17:06:00 +0530 Subject: [PATCH 2/2] Add per-container toggles: opt-in external-storage fastpath, disable libredirect (minimal W^X-only shim on modern) --- .../ui/screen/xserver/XServerScreen.kt | 11 ----------- .../BionicProgramLauncherComponent.java | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt index 8a7992f3ab..09a15df78b 100644 --- a/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt +++ b/app/src/main/java/app/gamenative/ui/screen/xserver/XServerScreen.kt @@ -3921,17 +3921,6 @@ private fun setupXEnvironment( envVars.remove("VKD3D_FRAME_RATE") if (!envVars.has("WINEESYNC")) envVars.put("WINEESYNC", "1") - if (container.isFasterExternalLoading) { - val ffpGameDir = runCatching { - Container.drivesIterator(container.drives).asSequence() - .firstOrNull { it[0] == "A" }?.let { File(it[1]).canonicalFile.path } - }.getOrNull() ?: "" - if (ffpGameDir.startsWith("/storage/") && !ffpGameDir.startsWith("/storage/emulated/")) { - envVars.put("FFP_ENABLE", "1") - envVars.put("FFP_MARKERS", "/steamapps/common/;/dosdevices/a:") - } - } - val graphicsDriverConfig = KeyValueSet(container.getGraphicsDriverConfig()) if (graphicsDriverConfig.get("version").lowercase(Locale.getDefault()).contains("gen8")) { var tuDebug = envVars.get("TU_DEBUG") diff --git a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java index acb219cb06..ab0532710e 100644 --- a/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java +++ b/app/src/main/java/com/winlator/xenvironment/components/BionicProgramLauncherComponent.java @@ -327,6 +327,25 @@ private int execGuestProgram() { envVars.put("EVSHIM_WINE", 1); envVars.put("EVSHIM_SHM_NAME", "controller-shm0"); + if (container != null && container.isFasterExternalLoading()) { + String ffpGameDir = null; + for (String[] drive : Container.drivesIterator(container.getDrives())) { + if (drive[0].equals("A")) { + try { + ffpGameDir = new File(drive[1]).getCanonicalPath(); + } catch (IOException e) { + ffpGameDir = drive[1]; + } + break; + } + } + if (ffpGameDir != null && ffpGameDir.startsWith("/storage/") + && !ffpGameDir.startsWith("/storage/emulated/")) { + envVars.put("FFP_ENABLE", "1"); + envVars.put("FFP_MARKERS", "/steamapps/common/;/dosdevices/a:"); + } + } + // Check for specific shared memory libraries // if ((new File(imageFs.getLibDir(), "libandroid-sysvshm.so")).exists()){ // ld_preload = imageFs.getLibDir() + "/libandroid-sysvshm.so";