We are running into issues with an old closed-source game engine failing to compile shaders when memory nears 2GB.
The issue is usually with D3DXCreateEffect
. Usually it returns HResult "out of memory", sometimes d3dx9_25.dll
prints random errors in a popup, or it just outright segfault.
I believe the issue is lack of Large Address Awareness: I noticed one of the d3dx9_25.dll
crashes doing something that would hint as such. It took a valid pointer that looked like 0x8xxxxxx3
, checked that bits 0x80000003
are lit and if yes, it bit inverts the pointer and derefs it. The resulting pointer pointed to unallocated memory. Forcing the engine to malloc 2GB before compilation makes the shaders fail to compile every time.
Unfortunately our knowledge of DX9 is very limited, I've seen that DX9 has a flag D3DXCONSTTABLE_LARGEADDRESSAWARE
but I'm not sure where exactly Its supposed to go. The only API call the game uses that I can find relies on it is D3DXGetShaderConstantTable
, but the issues happen before it is ever called. Injecting the flag (1 << 17) = 0x20000
to D3DXCreateEffect
makes the shader fail compilation in another way.
Is D3DXCreateEffect
supposed to accept the Large Address Aware flag? I found a wine test using it, but digging into DX9 assembly, the error it throws is caused by an internal function returning HResult Invalid Call when any bit out of FFFFF800
in flags is set, which leads me to believe CreateEffect
is not supposed to accept this flag.
Is there anywhere else I should be injecting the Large Address Aware flag before this? I understand that a call to D3DXGetShaderConstantTable
will need to be fixed to use D3DXGetShaderConstantTableEx
, but its not even reached yet.
LargeAddressAware is a bit of a hack, so it may or may not help your case. It really only helps if your application needs a little more room close to 2GB of VA, not if if needs a lot more.
A key problem with the legacy DirectX SDK Direct3D 9 era effects system is that it assumed the high-bit of the effect "handle" was free so it could use it, and without the bit the handle was an address to a string. This assumption is not true for LargeAddressAware.
To enable this, you define D3DXFX_LARGEADDRESS_HANDLE
before including d3dx9.h
headers. You then must use the D3DXFX_LARGEADDRESSAWARE
flag when creating all effects. You must also not use the alias trick where you can use a "string name" instead of a "handle" on all the effect methods. Instead you have to use GetParameterByName
to get the handle and use that instead.
What I can't remember is when the LAA flag was added to Effects for Direct3D 9.
If you are using d3dx9_25.dll
then that's the April 2005 release of the DirectX SDK. If you are using "Pixel Shader Model 1.x" then you can't use any version newer than d3dx9_31.dll
(October 2006)--later versions of the DirectX SDK let you use D3DXSHADER_USE_LEGACY_D3DX9_31_DLL
which just passed through shader compilation to the older version for this scenario.
A key reason that many 32-bit games would fail and then work with LAA enabled was because of virtual memory fragmentation. Improving your VA memory layout can making your allocations more uniform can help too.
The issue we were having with CreateEffect
not accepting the LargeAddressAware
flag is pretty obvious in hindsight, the dx9 version the engine is using (d3dx9_25.dll
) simply did not have this feature yet.
Our options, other than optimizing our memory usage are:
Convert all our pixel shaders 1.x to 2.0 and force the engine to load a newer version of d3dx9, hope the engine is not relying on bugs of d3dx9_25.dll
or the alias trick, then inject the LargeAddressAware flag bit there.
Wrap malloc, either avoiding giving handles large addresses (I am unsure if this is also required inside the dll as well) or stick enough other data in large addresses so dx9 related mallocs don't reach it.
User contributions licensed under CC BY-SA 3.0