Skip to content

Make the engine NativeAOT / trim clean - #3204

Merged
xen2 merged 13 commits into
stride3d:masterfrom
xen2:feature/aot
Jun 4, 2026
Merged

xen2 merged 13 commits into
stride3d:masterfrom
xen2:feature/aot

Conversation

@xen2

@xen2 xen2 commented Jun 4, 2026

Copy link
Copy Markdown
Member

PR Details

Brings the Stride runtime to a state where a game publishes and runs under NativeAOT (and trimming)
with no ILC errors, and adds CI guards so it stays that way. The editor (WPF) is unaffected — AOT
applies to shipped games only.

What & why

NativeAOT/trim support benefits every AOT target (iOS, consoles, lean desktop builds). Getting there
meant removing reflection/AOT-hostile patterns from the runtime, making optional/desktop-only
subsystems trimmable behind feature switches, and proving it with an end-to-end test.

Key changes

Engine AOT-cleanliness

  • Trim/AOT-root serializers; EnumSerializer uses Unsafe.SizeOf<T> instead of Marshal.SizeOf.
  • AOT-root data-type/processor ctors; reflection-free ParameterKey subkeys.
  • Drain trim warnings ([DynamicallyAccessedMembers] where real, justified suppressions where safe).

Optional subsystems become trimmable (feature switches)

  • Feature-switch the windowing backends (WinFormsBackendEnabled / SDLBackendEnabled) and gate the
    whole Win32 controller stack (DirectInput/XInput/raw input) behind WinFormsBackendEnabled.
  • RemoteEffectCompilerEnabled (Game Studio shader socket) defaults off under PublishAot/
    PublishTrimmed via Stride.Engine/buildTransitive; opt back in with -p:StrideRemoteEffectCompilerEnabled=true.

Bug fixes surfaced by AOT

  • input: detect XInput devices via the Raw Input API instead of WMI — drops
    Microsoft.Management.Infrastructure, whose native delegate marshalling crashed an AOT game at startup.
  • audio: SoundBase.Destroy disposes source voices before freeing buffers — fixes an XAudio2 teardown
    access violation.

Test guards (Stride.Samples.Tests, Direct3D11)

  • TopDownRPGAot — AOT-publishes a sample and runs it through the same capture + LPIPS compare as the
    JIT lane (catches ILC failures, reflection-serialization regressions, native teardown crashes).
  • TopDownRPGTrimsWinForms — publishes trimmed with WinForms disabled and asserts System.Windows.Forms.dll
    is trimmed out (proves the gating actually drops it).
  • AOT-clean test harness (fixtures self-register via [ModuleInitializer], AOT-safe done.json writer),
    a shared NativeCrashHandler, and post-done crash reporting. CI sets STRIDE_TESTS_CRASH_DUMPS=1.

Docs

  • docs/build/aot.md — publishing AOT/trimmed games, the feature switches, contributor guidance.
  • docs/debugging/native-crashes.md — capturing/analyzing native AVs (GPU/audio/AOT).

Testing

  • TopDownRPGAot passes: publishes, renders, captures, LPIPS-matches baseline, exits clean.
  • TopDownRPGTrimsWinForms passes: trimmed publish drops System.Windows.Forms.dll (verified the
    publish dir contained the app exe + 108 framework DLLs, with WinForms absent).

Related Issue

Types of changes

  • Docs change / refactoring / dependency upgrade
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My change requires a change to the documentation.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • I have built and run the editor to try this change out.

@xen2

xen2 commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

/ci e2e

xen2 added 13 commits June 4, 2026 15:40
…ppressions for name-resolved/single-file paths)
Drop the unused UseWPF and gate GameWindowWinforms + raw input behind WinFormsBackendEnabled so the WindowsDesktop pack can be trimmed.
Lets AOT/trim drop the Game Studio socket stack.
Fixtures register via [ModuleInitializer] and the runner uses the registered instance instead of an assembly scan. Harness wiring lives in SampleAutoTesting.targets.template, version-filled by the orchestrator. Adds Stride.Games.AutoTesting to build/Stride.sln.
…oTesting

Extract SetErrorMode + FirstChanceException minidump capture into sources/shared/NativeCrashHandler.cs, used by both. Also fixes Graphics.Regression setting SEM_NOGPFAULTERRORBOX unconditionally, which blocked dump capture for pure-native crashes; the shared handler gates it off in capture mode.
Flag a clean run (status=ok) that exits non-zero or is timeout-killed after
writing done.json as crashed-after-done, so a late or native teardown crash
can't pass silently.
RunOne(aot:true) publishes the sample with PublishAot (self-contained, win-x64) and runs the
native exe through the same capture + LPIPS compare; the VS Installer dir is prepended to PATH so
the ILC link step finds vswhere. New always-run TopDownRPGAot fact (Direct3D11 only). CI sets
STRIDE_TESTS_CRASH_DUMPS=1 so the harness's native-crash capture isn't suppressed.
Replace the CimSession/WQL query in the DirectInput source with a GetRawInputDeviceList
enumeration (user32). Drops the Microsoft.Management.Infrastructure dependency, whose native
delegate marshalling isn't NativeAOT-compatible and crashed an AOT-published game at startup.
docs/build/aot.md — publishing AOT/trimmed games, the feature switches that drop optional subsystems,
and contributor guidance for keeping the engine AOT-clean. docs/debugging/native-crashes.md — capturing
and analyzing native access violations (GPU/audio/AOT) that crash silently.
@stride3d stride3d deleted a comment from stride-chatops Bot Jun 4, 2026
@stride3d stride3d deleted a comment from stride-chatops Bot Jun 4, 2026
@xen2

xen2 commented Jun 4, 2026

Copy link
Copy Markdown
Member Author

/ci e2e

@stride-chatops

stride-chatops Bot commented Jun 4, 2026 •

Copy link
Copy Markdown

@xen2 — /ci dispatched:

⚠️ This PR modifies workflow YAML used by /ci, but the bot runs master's version:

Land workflow changes on master first if you need them tested.

@stride-chatops

stride-chatops Bot commented Jun 4, 2026

Copy link
Copy Markdown

@xen2
xen2 merged commit 244f744 into stride3d:master Jun 4, 2026
24 of 25 checks passed
@xen2
xen2 deleted the feature/aot branch June 4, 2026 07:39
xen2 added a commit to xen2/stride that referenced this pull request Jul 16, 2026
* core: trim/AOT-root serializers + EnumSerializer Unsafe.SizeOf

* engine: AOT-root data-type/processor ctors + reflection-free ParameterKey subkeys

* engine: drain trim warnings (DAM on factory/proxy ctors; justified suppressions for name-resolved/single-file paths)

* engine: drain remaining trim warnings (justified suppressions for AssemblyProcessor-rooted reflection paths)

* engine: feature-switch windowing backends (WinForms/SDL) for AOT/trim

* engine: gate WinForms/WPF windowing for AOT/trim

Drop the unused UseWPF and gate GameWindowWinforms + raw input behind WinFormsBackendEnabled so the WindowsDesktop pack can be trimmed.

* engine: gate remote effect compiler behind RemoteEffectCompilerEnabled

Lets AOT/trim drop the Game Studio socket stack.

* autotesting: AOT-clean harness, fixtures self-register

Fixtures register via [ModuleInitializer] and the runner uses the registered instance instead of an assembly scan. Harness wiring lives in SampleAutoTesting.targets.template, version-filled by the orchestrator. Adds Stride.Games.AutoTesting to build/Stride.sln.

* tests: share native crash handler between Graphics.Regression and AutoTesting

Extract SetErrorMode + FirstChanceException minidump capture into sources/shared/NativeCrashHandler.cs, used by both. Also fixes Graphics.Regression setting SEM_NOGPFAULTERRORBOX unconditionally, which blocked dump capture for pure-native crashes; the shared handler gates it off in capture mode.

* tests: report post-done crashes in screenshot orchestrator

Flag a clean run (status=ok) that exits non-zero or is timeout-killed after
writing done.json as crashed-after-done, so a late or native teardown crash
can't pass silently.

* tests: AOT publish+run lane for sample screenshots

RunOne(aot:true) publishes the sample with PublishAot (self-contained, win-x64) and runs the
native exe through the same capture + LPIPS compare; the VS Installer dir is prepended to PATH so
the ILC link step finds vswhere. New always-run TopDownRPGAot fact (Direct3D11 only). CI sets
STRIDE_TESTS_CRASH_DUMPS=1 so the harness's native-crash capture isn't suppressed.

* input: detect XInput devices via Raw Input instead of WMI

Replace the CimSession/WQL query in the DirectInput source with a GetRawInputDeviceList
enumeration (user32). Drops the Microsoft.Management.Infrastructure dependency, whose native
delegate marshalling isn't NativeAOT-compatible and crashed an AOT-published game at startup.

* docs: NativeAOT/trimming guide + native-crash debugging

docs/build/aot.md — publishing AOT/trimmed games, the feature switches that drop optional subsystems,
and contributor guidance for keeping the engine AOT-clean. docs/debugging/native-crashes.md — capturing
and analyzing native access violations (GPU/audio/AOT) that crash silently.
@xen2 xen2 mentioned this pull request Aug 11, 2026
2 of 8 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant