-
-
Notifications
You must be signed in to change notification settings - Fork 403
Speed up external #1773
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
Speed up external #1773
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -3658,6 +3658,12 @@ private fun setupXEnvironment( | |||||||||||||||||
| envVars.remove("DXVK_FRAME_RATE") | ||||||||||||||||||
| envVars.remove("VKD3D_FRAME_RATE") | ||||||||||||||||||
| if (!envVars.has("WINEESYNC")) envVars.put("WINEESYNC", "1") | ||||||||||||||||||
|
|
||||||||||||||||||
| val ffpGameDir = runCatching { | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: This FFP_ENABLE logic only resolves the game directory through Prompt for AI agents |
||||||||||||||||||
| File(SteamService.getAppDirPath(ContainerUtils.extractGameIdFromContainerId(appId))).canonicalFile.path | ||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: The Since Prompt for AI agents |
||||||||||||||||||
| }.getOrDefault("") | ||||||||||||||||||
| if (ffpGameDir.startsWith("/storage/")) envVars.put("FFP_ENABLE", "1") | ||||||||||||||||||
|
Comment on lines
+3662
to
+3665
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚀 Performance & Scalability | 🟡 Minor | ⚡ Quick win Use the container’s resolved game drive, not a Steam-only lookup. This executes for GOG, Epic, Amazon, and custom games too, but always queries Proposed fix-val ffpGameDir = runCatching {
- File(SteamService.getAppDirPath(ContainerUtils.extractGameIdFromContainerId(appId))).canonicalFile.path
-}.getOrDefault("")
+val ffpGameDir = ContainerUtils.getADrivePath(container.drives)
+ ?.let { runCatching { File(it).canonicalFile.path }.getOrNull() }
+ .orEmpty()
if (ffpGameDir.startsWith("/storage/")) envVars.put("FFP_ENABLE", "1")📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||
|
|
||||||||||||||||||
| val graphicsDriverConfig = KeyValueSet(container.getGraphicsDriverConfig()) | ||||||||||||||||||
| if (graphicsDriverConfig.get("version").lowercase(Locale.getDefault()).contains("gen8")) { | ||||||||||||||||||
| var tuDebug = envVars.get("TU_DEBUG") | ||||||||||||||||||
|
|
||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -98,6 +98,55 @@ object StorageUtils { | |||||||||||||||||||||||||||||||||||||
| return result | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| private const val PUBLIC_INSTALL_DIR_NAME = "GameNative" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Maps an app-specific dir (<volume>/Android/data/<pkg>/files) to a public install root | ||||||||||||||||||||||||||||||||||||||
| * (<volume>/GameNative). MediaProvider disables FUSE kernel caching under Android/data, | ||||||||||||||||||||||||||||||||||||||
| * making per-open metadata ops ~1000x slower there; public dirs get normal dcache treatment. | ||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||
| fun publicInstallRoot(appFilesDir: File): File? { | ||||||||||||||||||||||||||||||||||||||
| val path = appFilesDir.absolutePath | ||||||||||||||||||||||||||||||||||||||
| val idx = path.indexOf("/Android/data/") | ||||||||||||||||||||||||||||||||||||||
| if (idx <= 0) return null | ||||||||||||||||||||||||||||||||||||||
| return File(path.substring(0, idx), PUBLIC_INSTALL_DIR_NAME) | ||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Modern builds select a root-level shared-storage directory they cannot create or write on Android 11+, so external installs silently fall back here or later download operations fail. Keep modern installs app-scoped, or gate this public-root path behind the existing legacy all-files-access flow. Prompt for AI agents |
||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun ensureInstallRoot(dir: File): Boolean { | ||||||||||||||||||||||||||||||||||||||
| if (!dir.isDirectory && !dir.mkdirs()) return false | ||||||||||||||||||||||||||||||||||||||
| runCatching { File(dir, ".nomedia").createNewFile() } | ||||||||||||||||||||||||||||||||||||||
| return true | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun preferredInstallRoot(appFilesDir: File): String { | ||||||||||||||||||||||||||||||||||||||
| val public = publicInstallRoot(appFilesDir) | ||||||||||||||||||||||||||||||||||||||
| if (public != null && ensureInstallRoot(public)) return public.absolutePath | ||||||||||||||||||||||||||||||||||||||
| return appFilesDir.absolutePath | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| fun migrateLegacyGameDir(path: String?): String? { | ||||||||||||||||||||||||||||||||||||||
| if (path.isNullOrBlank()) return path | ||||||||||||||||||||||||||||||||||||||
| val idx = path.indexOf("/Android/data/") | ||||||||||||||||||||||||||||||||||||||
| if (idx <= 0) return path | ||||||||||||||||||||||||||||||||||||||
| val filesIdx = path.indexOf("/files/", idx) | ||||||||||||||||||||||||||||||||||||||
| if (filesIdx < 0) return path | ||||||||||||||||||||||||||||||||||||||
| val legacyRoot = File(path.substring(0, filesIdx + "/files".length)) | ||||||||||||||||||||||||||||||||||||||
| val rel = path.substring(filesIdx + "/files/".length) | ||||||||||||||||||||||||||||||||||||||
| val src = File(path) | ||||||||||||||||||||||||||||||||||||||
| if (!src.isDirectory) return path | ||||||||||||||||||||||||||||||||||||||
| val publicRoot = publicInstallRoot(legacyRoot) ?: return path | ||||||||||||||||||||||||||||||||||||||
| val dst = File(publicRoot, rel) | ||||||||||||||||||||||||||||||||||||||
| if (dst.exists() || !ensureInstallRoot(publicRoot)) return path | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+135
to
+139
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Make legacy-path resolution idempotent. After a successful first migration, Proposed fix val src = File(path)
-if (!src.isDirectory) return path
val publicRoot = publicInstallRoot(legacyRoot) ?: return path
val dst = File(publicRoot, rel)
-if (dst.exists() || !ensureInstallRoot(publicRoot)) return path
+if (dst.isDirectory) return dst.absolutePath
+if (!src.isDirectory || dst.exists() || !ensureInstallRoot(publicRoot)) return path📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Comment on lines
+136
to
+139
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Prompt for AI agents
Suggested change
|
||||||||||||||||||||||||||||||||||||||
| dst.parentFile?.mkdirs() | ||||||||||||||||||||||||||||||||||||||
| return if (src.renameTo(dst)) { | ||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Migrated Epic, GOG, and Amazon games work for the migration launch but revert to their deleted legacy path on the next launch because the source-specific persisted install path is never updated. Persist the destination path with the game metadata as part of a successful migration, or resolve legacy paths to the destination when the source no longer exists. Prompt for AI agents |
||||||||||||||||||||||||||||||||||||||
| Timber.i("Migrated game dir $path to ${dst.absolutePath}") | ||||||||||||||||||||||||||||||||||||||
| dst.absolutePath | ||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||
| Timber.w("Could not migrate $path; leaving in place") | ||||||||||||||||||||||||||||||||||||||
| path | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||
| * Gets all app-specific external files directories, using StorageManager as a fallback | ||||||||||||||||||||||||||||||||||||||
| * for cases where context.getExternalFilesDirs(null) might return null or incomplete results | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,7 +43,7 @@ | |
| import java.util.concurrent.atomic.AtomicLong; | ||
|
|
||
| public abstract class ImageFsInstaller { | ||
| public static final byte LATEST_VERSION = 28; | ||
| public static final byte LATEST_VERSION = 29; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Do not mark the imagefs latest when guest-library deployment fails. With Make 🤖 Prompt for AI Agents
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Bumping Prompt for AI agents |
||
|
|
||
| private static void resetContainerImgVersions(Context context) { | ||
| ContainerManager manager = new ContainerManager(context); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: Interrupted GOG, Epic, and Amazon downloads on existing external installs stop being resumable after startup. This repoints the sole external root without migrating legacy partial directories or retaining the old root in each service’s scan set; migrate those directories before updating the preference, or preserve the legacy root for discovery.
Prompt for AI agents