A tester ran 4.12.233 under Proton and it died on first mission load. The
cause turned out to name itself, and to be a Windows bug we have been
shipping the whole time.
Wine implements d3dx9_43 itself, and 63 of its 329 exports are stubs. The
game imports twenty of them and exactly one is stubbed:
D3DXConcatenateMeshes, called once per session from
ConsolidateStaticObjects on the first-mission-load latch - so every player
hits it on their first race. Wine raised EXCEPTION_WINE_STUB naming the
function in plain text, and our own crash filter caught it and wrote a
minidump, which is how a self-describing failure arrived as a mystery.
The fix is one file, and it was overdue on Windows. d3dx9_43.dll is a HARD
import of the exe - only steam_api.dll is delay-loaded - and it is not part
of Windows. It ships with the June 2010 DirectX End-User Runtime and
nothing else. Any customer on a clean Windows 10 or 11 who never installed
that redistributable cannot start the game at all: the loader fails at
0xC0000135 before WinMain, no window, no log line. Every machine this has
been built or tested on had the SDK or some older game installed, which is
precisely why nobody has ever seen it. pack-dist now extracts the DLL from
the SDK's redist cab into dist. Wine prefers an application-directory DLL
over its builtin, so the same file closes the Windows failure and the Linux
blocker together, and it is verified working on a stock prefix with nothing
installed. The SDK terms nominate DXSETUP as the delivery method for this
redistributable; the loose DLL is what is verified and is near-universal
practice, but that wants confirming before a public release.
/LARGEADDRESSAWARE, because the same session reported VmSize 3193MB and an
older Wine that died before video init with the address space exhausted.
The game is not using that memory: measured here, a standalone mission
peaks at 166MB committed against 795MB of address space. The gap is
reservations, mapped files, and mostly the graphics driver mapping VRAM
apertures into our process - under wined3d's OpenGL path that grows several
times over. For a 32-bit process the 2GB address ceiling is a hard limit
with nothing to do with RAM, so it is entirely possible to run out of
addresses while using 170MB. The flag raises it to 4GB, frees nothing, and
changes no behaviour. Worth having on Windows too: 795MB of 2GB is already
40% before 1080p, eight pods, and the 100MB buffer RP412RECORDSIZE takes
when recording is armed.
And two diagnostics so the next one costs a log line instead of an
investigation. The crash filter now decodes 0x80000100 and writes the
offending module.function before the minidump; startup probes
wine_get_version in ntdll and logs the platform beside the version banner.
Neither can appear on Windows - verified: the smoke run's log has the
version line and no platform line.
Not fixed here, deliberately: the durable version of this is to write the
mesh merge by hand, since D3DXSimplifyMesh and D3DXSplitMesh are stubs too
and any future mesh work hits the same wall. And the field test ran
wined3d, not DXVK, so the child-window Present with GDI panes clipped over
it - the risk the assessment led with - is still untested. The doc records
both, along with the prediction it got wrong: the windowsapp.lib import was
called a load-time failure risk under Wine, and it simply is not one.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>