我们遇到了一个老的闭源游戏引擎的问题,当内存接近2GB时,它无法编译着色器。
问题通常出现在D3DXCreateEffect
上。通常会返回 "内存不足" 的 HResult,有时d3dx9_25.dll
弹出随机错误的窗口或者直接崩溃。
我认为问题是缺乏大地址感知:我注意到其中一个d3dx9_25.dll
崩溃做了一些暗示这样的事情。它获取了一个看起来像0x8xxxxxx3
的有效指针,检查位0x80000003
是否亮起,如果亮起,它将反转位并取消引用。结果指针指向未分配的内存。在编译之前强制引擎malloc 2GB会导致着色器每次都无法编译。
不幸的是,我们对DX9的了解非常有限,我发现DX9有一个标记为D3DXCONSTTABLE_LARGEADDRESSAWARE
的标志,但我不确定它应该放在哪里。我能找到的唯一使用它的API调用是D3DXGetShaderConstantTable
,但问题发生在它被调用之前。将标志(1 << 17) = 0x20000
注入到D3DXCreateEffect
中会导致着色器以另一种方式无法编译。
D3DXCreateEffect
函数是否可以接受Large Address Aware标志?我找到了一个使用该标志的测试,但在研究DX9汇编时,当flags中的任何一位超出FFFFF800
时,它引发的错误是由内部函数返回HResult Invalid Call引起的,这让我认为CreateEffect
函数不应该接受此标志。在此之前,我是否应该在其他地方注入Large Address Aware标志?我知道需要修复对
D3DXGetShaderConstantTable
的调用以使用D3DXGetShaderConstantTableEx
,但它甚至还没有被执行到。
0x80000003
中的“3”。这暗示了一个未对齐的指针。取反它不会使其对齐,但是反转所有位可以。 - MSaltersneg
表示进行二进制补码取反(从零开始减),在C语言中对应一元运算符-
。x86指令集中的not
则表示进行二进制反码取反,即将所有位取反,在C语言中对应按位取反运算符~
。我们称后者为按位取反,而不是取反操作,以便区分数学/二进制补码的取反操作。 - Peter Cordes