-
Notifications
You must be signed in to change notification settings - Fork 0
Android: stop nudging SurfaceView into a recreate cycle during Vulkan init #243
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
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 | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -37,9 +37,25 @@ internal static class CrashDiagnostics | |||||||||||||||||||||||||||||||||
| private static int initialised; | ||||||||||||||||||||||||||||||||||
| private static int managedHooksInstalled; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Global cap on FirstChanceException dumps written per process. A hot-path | ||||||||||||||||||||||||||||||||||
| // throw loop (e.g. Veldrid "surface lost" thrown every Draw frame while the | ||||||||||||||||||||||||||||||||||
| // Android Vulkan surface is unavailable during a slow startup) can otherwise | ||||||||||||||||||||||||||||||||||
| // produce hundreds of full-stack dumps, each one a synchronous file write | ||||||||||||||||||||||||||||||||||
| // on the throwing thread — which itself stalls the Draw thread and worsens | ||||||||||||||||||||||||||||||||||
| // the very condition causing the throws. | ||||||||||||||||||||||||||||||||||
| private const int first_chance_global_cap = 50; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // Per-unique-stack cap. Higher (10) for true fatal kinds caught via | ||||||||||||||||||||||||||||||||||
| // FirstChanceException-fallback or AppDomain.UnhandledException; lower (3) | ||||||||||||||||||||||||||||||||||
| // for first-chance noise where seeing the first few occurrences is enough | ||||||||||||||||||||||||||||||||||
| // to diagnose and the rest are pure log bloat. | ||||||||||||||||||||||||||||||||||
| private const int per_key_cap_default = 10; | ||||||||||||||||||||||||||||||||||
| private const int per_key_cap_first_chance = 3; | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+53
|
||||||||||||||||||||||||||||||||||
| private const int first_chance_global_cap = 50; | |
| // Per-unique-stack cap. Higher (10) for true fatal kinds caught via | |
| // FirstChanceException-fallback or AppDomain.UnhandledException; lower (3) | |
| // for first-chance noise where seeing the first few occurrences is enough | |
| // to diagnose and the rest are pure log bloat. | |
| private const int per_key_cap_default = 10; | |
| private const int per_key_cap_first_chance = 3; | |
| private const int FIRST_CHANCE_GLOBAL_CAP = 50; | |
| // Per-unique-stack cap. Higher (10) for true fatal kinds caught via | |
| // FirstChanceException-fallback or AppDomain.UnhandledException; lower (3) | |
| // for first-chance noise where seeing the first few occurrences is enough | |
| // to diagnose and the rest are pure log bloat. | |
| private const int PER_KEY_CAP_DEFAULT = 10; | |
| private const int PER_KEY_CAP_FIRST_CHANCE = 3; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,6 +88,14 @@ | |
| private object? activeMixersList; | ||
|
|
||
| private object? nativeBridges; | ||
|
|
||
| /// <summary> | ||
| /// Last value passed to <see cref="OsuGameActivity.RequestedOrientation"/> by | ||
|
Check warning on line 93 in osu.Android/OsuGameAndroid.cs
|
||
| /// <see cref="updateOrientation"/>. Cached locally so we can short-circuit | ||
| /// redundant updates without round-tripping through the activity getter, which | ||
| /// itself performs a binder IPC on modern Android. | ||
| /// </summary> | ||
| private global::Android.Content.PM.ScreenOrientation? lastRequestedOrientation; | ||
|
Comment on lines
+92
to
+98
|
||
| private int currentRefreshRate; | ||
|
|
||
| public OsuGameAndroid(OsuGameActivity activity) | ||
|
|
@@ -753,24 +761,44 @@ | |
|
|
||
| var orientation = MobileUtils.GetOrientation(this, currentScreen, gameActivity.IsTablet); | ||
|
|
||
| global::Android.Content.PM.ScreenOrientation desired; | ||
|
|
||
| switch (orientation) | ||
| { | ||
| case MobileUtils.Orientation.Locked: | ||
| desired = global::Android.Content.PM.ScreenOrientation.Locked; | ||
| break; | ||
|
|
||
| case MobileUtils.Orientation.Portrait: | ||
| desired = global::Android.Content.PM.ScreenOrientation.Portrait; | ||
| break; | ||
|
|
||
| case MobileUtils.Orientation.Default: | ||
| desired = gameActivity.DefaultOrientation; | ||
| break; | ||
|
|
||
| default: | ||
| return; | ||
| } | ||
|
|
||
| // Short-circuit when no change is required. We track the last requested orientation | ||
| // locally because Activity.getRequestedOrientation() itself performs a binder IPC | ||
| // on modern Android, and the whole point of this guard is to avoid binder traffic. | ||
| // ScreenChanged fires on every screen push/pop and the resolved orientation rarely | ||
| // differs between adjacent screens, so without this guard we flood the UI looper | ||
| // with redundant Activity.setRequestedOrientation transactions, which under | ||
| // system_server CPU pressure can wedge input dispatch and trigger an ANR | ||
| // ("Input dispatching timed out ... Waited 10000ms for MotionEvent"). | ||
| if (lastRequestedOrientation == desired) | ||
| return; | ||
|
|
||
| lastRequestedOrientation = desired; | ||
|
|
||
|
Comment on lines
+792
to
+796
|
||
| gameActivity.RunOnUiThread(() => | ||
| { | ||
| try | ||
| { | ||
| switch (orientation) | ||
| { | ||
| case MobileUtils.Orientation.Locked: | ||
| gameActivity.RequestedOrientation = global::Android.Content.PM.ScreenOrientation.Locked; | ||
| break; | ||
|
|
||
| case MobileUtils.Orientation.Portrait: | ||
| gameActivity.RequestedOrientation = global::Android.Content.PM.ScreenOrientation.Portrait; | ||
| break; | ||
|
|
||
| case MobileUtils.Orientation.Default: | ||
| gameActivity.RequestedOrientation = gameActivity.DefaultOrientation; | ||
| break; | ||
| } | ||
| gameActivity.RequestedOrientation = desired; | ||
| } | ||
| catch (Exception e) | ||
| { | ||
|
|
||
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.
The class-level documentation says managed-exception dumps are written to both internal and external storage "in real time", but the new first-chance path deliberately skips external writes. Update the docs near this new throttling/capping logic to reflect that first-chance exceptions are internal-only and only mirrored to external on next startup.