Skip to content

Game details: per-game AVX and AVX2 (MADEIRA_FEX_AVX) - #172

Merged
willfaust merged 1 commit into
willfaust:mainfrom
bahacan16:pr/fex-avx-opt-in
Oct 4, 2026
Merged

willfaust merged 1 commit into
willfaust:mainfrom
bahacan16:pr/fex-avx-opt-in

Conversation

@bahacan16

Copy link
Copy Markdown
Contributor

Problem

FEX's iOS build synthesizes its host features by hand (FetchHostFeatures, FEX_IOS_HOST) and never sets SupportsAVX, and it returns before any config override is read. Games that check CPUID take their SSE paths, which is the right default. Games compiled for AVX processors do not check: Ghost of Tsushima died on its first VEX instruction with STATUS_ILLEGAL_INSTRUCTION (c000001d) before reaching its menu.

Change

Needs a companion change in willfaust/FEX (FEX-avx-opt-in.md, patch FEX.patch): with MADEIRA_FEX_AVX=1 in the environment, the iOS FetchHostFeatures sets SupportsAVX (and SupportsAES256 when AES is there) for the ARM64EC module; WOW64 stays without AVX, as on every other FEX host.

App side (this PR):

  • LibraryEntry.avx (optional, so older library files decode).
  • Game details › Compatibility & performance › AVX and AVX2, off by default; the section footer says when to use it and that emulated AVX is slower.
  • applyEnvironment sets MADEIRA_FEX_AVX=1 for that game or unsets it, so one game's choice never stays for the next session.
  • docs/LIBRARY.md: one bullet.

Evidence

Fork builds since 2026-09-26 (iPhone 17 Pro Max, iOS 27):

  • Ghost of Tsushima (D3D12) ran with AVX on through intros, the main menu and into gameplay in every later session; without it the game stops at its first VEX instruction.
  • GTA V Enhanced: with AVX on, the processor feature set the guest sees carries the AVX bits (FeatureSet 0xe3f9ffff in the fork's hardware-description log line); with AVX off the game still passes its own CPU checks and its Chromium helpers log that they take their SSE paths. Titles differ, which is why this is a per-game switch and not a default.

Notes / risks

  • Off by default; nothing changes for a game that does not choose it.
  • Without the FEX change the switch only sets a variable nothing reads.
  • Binary to rebuild after the FEX PR: app/Madeira/arm64ec-windows/xtajit64.dll (build/fex-arm64ec). The fork shipped a second copy (xtajit64-avx.dll) and switched links per game at first; that is not needed, since the module itself reads the variable at start-up, and is not ported.
  • No new Swift file; project.pbxproj unchanged.

🤖 Generated with Claude Code

Claude-Session: https://claude.ai/code/session_0189oLHghpaYKLk4f786a6bc

## Problem

FEX's iOS build synthesizes its host features by hand (`FetchHostFeatures`, `FEX_IOS_HOST`) and never sets `SupportsAVX`, and it returns before any config override is read. Games that check CPUID take their SSE paths, which is the right default. Games compiled for AVX processors do not check: **Ghost of Tsushima** died on its first VEX instruction with `STATUS_ILLEGAL_INSTRUCTION` (c000001d) before reaching its menu.

## Change

Needs a companion change in **willfaust/FEX** (`FEX-avx-opt-in.md`, patch `FEX.patch`): with `MADEIRA_FEX_AVX=1` in the environment, the iOS `FetchHostFeatures` sets `SupportsAVX` (and `SupportsAES256` when AES is there) for the ARM64EC module; WOW64 stays without AVX, as on every other FEX host.

App side (this PR):

- `LibraryEntry.avx` (optional, so older library files decode).
- **Game details › Compatibility & performance › AVX and AVX2**, off by default; the section footer says when to use it and that emulated AVX is slower.
- `applyEnvironment` sets `MADEIRA_FEX_AVX=1` for that game or unsets it, so one game's choice never stays for the next session.
- `docs/LIBRARY.md`: one bullet.

## Evidence

Fork builds since 2026-09-26 (iPhone 17 Pro Max, iOS 27):

- Ghost of Tsushima (D3D12) ran with AVX on through intros, the main menu and into gameplay in every later session; without it the game stops at its first VEX instruction.
- GTA V Enhanced: with AVX on, the processor feature set the guest sees carries the AVX bits (`FeatureSet 0xe3f9ffff` in the fork's hardware-description log line); with AVX off the game still passes its own CPU checks and its Chromium helpers log that they take their SSE paths. Titles differ, which is why this is a per-game switch and not a default.

## Notes / risks

- Off by default; nothing changes for a game that does not choose it.
- Without the FEX change the switch only sets a variable nothing reads.
- Binary to rebuild after the FEX PR: `app/Madeira/arm64ec-windows/xtajit64.dll` (`build/fex-arm64ec`). The fork shipped a second copy (`xtajit64-avx.dll`) and switched links per game at first; that is not needed, since the module itself reads the variable at start-up, and is not ported.
- No new Swift file; `project.pbxproj` unchanged.

---
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0189oLHghpaYKLk4f786a6bc
Signed-off-by: bahacan16 <190844990+bahacan16@users.noreply.github.com>
willfaust pushed a commit that referenced this pull request Oct 4, 2026
Squashed from #172; needs willfaust/FEX#9.

Signed-off-by: bahacan16 <190844990+bahacan16@users.noreply.github.com>
willfaust added a commit that referenced this pull request Oct 4, 2026
Frame generation (#171) is no longer the only other one: the AVX choice
(#172) and a game's own config lines (#167) export settings too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@willfaust willfaust closed this Oct 4, 2026
@willfaust willfaust reopened this Oct 4, 2026
@willfaust
willfaust merged commit a70caf9 into willfaust:main Oct 4, 2026
willfaust added a commit that referenced this pull request Oct 4, 2026
Direct3D 12 and DXMT fixes, game launcher windows, per-game settings,
PlayStation controllers and save backups (#134-#172 and the FEX and DXMT
pull requests merged with them).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
spitefulowl added a commit to spitefulowl/Madeira that referenced this pull request Oct 4, 2026
A library game exports its own engine switches before the session starts
(LibraryEntry.applyEnvironment): MADEIRA_FASTSYNC and MADEIRA_FASTSYNC_SEM
(Fast synchronization, Fast semaphore waits), MADEIRA_CPU_COUNT,
DXMT_D9_ANISO_LIMIT, FEX_X87REDUCEDPRECISION (Reduced-precision x87),
MADEIRA_DINPUT_PAD (Controller: XInput and DirectInput), MADEIRA_FEX_AVX
(AVX and AVX2, willfaust#172) and MADEIRA_FRAMEGEN (Frame generation, willfaust#171). The
bridge then exported madeira.cfg's env.* lines with overwrite, so a cfg line
for the same key replaced the game's choice: `env.MADEIRA_FASTSYNC = auto`
undid a game's "Fast synchronization: off", and `env.MADEIRA_FEX_AVX = 0`
would undo its "AVX and AVX2", although its details page says the game's
setting applies. The values also stayed in the app's environment after the
session, so a later launch in the same app run (MADEIRA_ONE_SESSION_PER_RUN=0)
inherited them.

Now a cfg line for one of these keys is skipped, and logged as
`[madeira-env] ml1184 KEY=<game's> kept (the game's own setting);
madeira.cfg's <value> ignored`, when the game set that key for this launch;
the keys are unset when the session ends. Which keys the game set is noted
once, before the first cfg line is exported: testing getenv() at each line
would take a key's earlier cfg line for the game's own setting, so with two
lines for one key Wine would run with the first value while Settings
(madeira.cfg is last-line-wins) shows the last. A game's own config lines
(This game's config, willfaust#167) are exported after this loop and still win over
both; docs/LIBRARY.md states the order.

MADEIRA_DINPUT_PAD joined the list later (ml1240): the per-game DirectInput
choice now beats the cfg key too, the Session menu says that the choice
applies from the next launch (the DirectInput device is made at launch), and
docs/CONTROLLERS.md names it the picker's second choice (it said third).

check-frontend gains the DirectInput export checks, a source check that the
per-launch keys are noted before the cfg loop, and one that every key
applyEnvironment exports is in the list and unset at the session's end, so a
new switch on the game's page cannot be left out; check-dock-gdi-section
searches the longer export loop to its end.

Tagged ml1184 and ml1240. Built only: the 2026-09-30 and 2026-10-03 builds
carried ml1184/ml1240 with the per-line test, but no device log shows a kept
line; the snapshot before the loop is syntax-checked with the iOS SDK.
check-frontend and check-dock-gdi-section pass.

Signed-off-by: spitefulowl <spitefulowll@gmail.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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.

3 participants