将32位DirectX9应用转换为可识别大地址

问题描述

我们遇到了一个问题,即旧的封闭源代码游戏引擎在内存接近2GB时无法编译着色器。

问题通常出在D3DXCreateEffect上。通常,它会返回“内存不足”的HResult,有时d3dx9_25.dll会在弹出窗口中打印随机错误,或者仅显示段错误。

我认为问题出在缺乏大型地址意识:我注意到d3dx9_25.dll崩溃之一发生了某种暗示的事情。它使用了一个看起来像0x8xxxxxx3的有效指针,检查了0x80000003位是否点亮,如果是,则它位反转并取消引用该指针。结果指针指向未分配的内存。在编译之前强制引擎分配2GB内存会使着色器每次都无法编译。

不幸的是,我们对DX9的了解非常有限,我已经看到DX9带有标志D3DXCONSTTABLE_LARGEADDRESSAWARE,但是我不确定它到底应该去哪里。我可以找到的唯一依赖于该游戏的API调用是D3DXGetShaderConstantTable,但问题是在调用之前就发生了。将标志(1 << 17) = 0x20000注入D3DXCreateEffect会使着色器以另一种方式编译失败。

  1. D3DXCreateEffect是否应该接受大地址感知标志?我发现使用了wine test,但是深入DX9程序集时,它引发的错误是由内部函数在标志中FFFFF800中的任何一位被置位时返回HResult Invalid Call引起的,这导致我认为CreateEffect不应该接受此标志。

  2. 在此之前,我还有其他地方应该插入大地址感知标志吗?我了解对D3DXGetShaderConstantTable的调用需要固定才能使用D3DXGetShaderConstantTableEx,但尚未实现。

解决方法

LargeAddressAware有点黑,因此它可能会或可能不会对您的情况有所帮助。确实只有在您的应用程序需要多一点空间来接近2GB VA时才有帮助,如果需要更多空间,则无济于事。

旧版DirectX SDK Direct3D 9时代效果系统的一个关键问题是,它假定效果“句柄”的高位是免费的,因此可以使用它,而没有一点点,句柄就是字符串的地址。对于LargeAddressAware,此假设是不正确的。

要启用此功能,请在包含D3DXFX_LARGEADDRESS_HANDLE标头之前定义d3dx9.h。然后,在创建所有效果时必须使用D3DXFX_LARGEADDRESSAWARE标志。您还必须 不要使用别名技巧,在所有效果方法上都可以使用“字符串名称”代替“句柄”。相反,您必须使用GetParameterByName来获取该句柄并使用它。

我不记得的是何时将LAA标志添加到Direct3D 9的效果中。

如果您使用的是d3dx9_25.dll,则是2005年4月发布的DirectX SDK。如果您使用的是“ Pixel Shader Model 1.x”,则不能使用比d3dx9_31.dll(2006年10月)更高的任何版本-DirectX SDK的更高版本允许您使用刚刚通过的D3DXSHADER_USE_LEGACY_D3DX9_31_DLL通过着色器编译到此情况的旧版本。

许多32位游戏将失败并随后启用LAA的主要原因是由于虚拟内存碎片。改善VA内存布局可以使分配更均匀,也可以有所帮助。

,

事后看来,CreateEffect不接受LargeAddressAware标志的问题非常明显,引擎使用的dx9版本(d3dx9_25.dll)尚不具备此功能

除了优化内存使用以外,我们的选择还有:

  1. 将所有像素着色器1.x转换为2.0,并强制引擎加载较新版本的d3dx9,希望引擎不要依赖d3dx9_25.dll的错误或别名技巧,然后注入LargeAddressAware标志位在那里。

  2. 包装malloc,要么避免给句柄提供大地址(我不确定dll中是否也需要这样做),要么将足够的 other 数据保留在大地址中,以便与dx9相关的malloc没达到。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...