我似乎偶然发现了有关DirectX 12.0编程的问题,到目前为止还没有研究能够深入了解这个问题.因此,除了似乎还没有一个切实可行的解决方案之外,我一直在寻找问题.
要告诉你,我现在用C(不是C++)和编程,因为很明显,提供了DirectX 12头文件做支持C,沿着C++,虽然我已经遇到的问题是奇怪的,因为它似乎是设计不良的C,可能由于没有多少人用这种语言编写复杂的(特别是面向对象的)应用程序.
这是我的问题:我在D3D12设备初始化过程中有以下代码块:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = pThis->pRTVHeap->lpVtbl->GetCPUDescriptorHandleForHeapStart(pThis->pRTVHeap);
凡HRTV代表" 处理,以渲染目标视图 "(D3D12_CPU_DESCRIPTOR_HANDLE)和pRTVHeap代表" 指针到渲染目标视图堆 "(ID3D12DescriptorHeap).
这是C++的等价物 - 这很好用:
/* Get a handle to the memory location in the render target
view heap to identify where the render target views will be
located for the two back buffers */
hRTV = this->pRTVHeap->GetCPUDescriptorHandleForHeapStart();
没有编译时错误,但在运行时,在C中调用此方法(GetCPUDescriptorHandleForHeapStart)会触发堆栈损坏(ESP变为4字节错位).
我检查了方法的反汇编并记下了RET(返回)指令:
mov edi,edi push ebp mov ebp,esp mov ecx,dword ptr [ebp+8] mov eax,dword ptr [ecx+2Ch] cmp dword ptr [eax],2 jne 5029004A mov eax,dword ptr [ebp+0Ch] mov ecx,dword ptr [ecx+28h] mov dword ptr [eax],ecx jmp 50290055 push dword ptr [ebp+0Ch] call 5029005E mov eax,dword ptr [ebp+0Ch] pop ebp ret 8
对于那些熟悉汇编或者COM(组件对象模型)对象的__stdcall调用约定的人来说,在堆栈上传递的'this'指针是第一个参数(在这种情况下,也是唯一的参数)该方法使COM对象可以访问自己的数据.
下面的代码片段(也显示在上面代码片段的末尾)调用了我的混淆,理所当然,当运行时抛出'错位的ESP'错误时:
ret 8
在这种情况下,只传递一个参数,即'this'指针.指针的大小(在32位系统上 - 我目前的目标架构是x86)是4个字节(32位),那么为什么被调用者清理堆栈上的8个字节?
我称这是一个错误吗?Microsoft是否需要了解此问题?我错了吗?这对我来说是一个愚蠢的错误吗?
感谢您的时间,我希望知识比我更多的人可以在这个问题上给我启发,但请不要建议解决方案是用C++而不是C编写.我已经考虑过这个问题并得出结论认为它不应该在我的情况下,我认为这是一种懒惰的解决方法,特别是当我发现C允许更多的程序控制和(在我的情况下)更高效率时.
解
D3D12.DLL的调试符号显示得足够。命名约定(例如ID3D12DescriptionHeap::GetCPUDescriptorHandleForHeapStart
)强烈表明DLL是用C ++编写的。一个(隐藏的)第二个参数确实传递给该方法-指向输出结构的指针D3D12_CPU_DESCRIPTOR_HANDLE
(仅包含一个整数,别名为结构。我不知道他们为什么这样做)。我忘记了C ++与C的不同之处在于C ++可以将结构作为返回值返回,并且不能通过累加器(%EAX)寄存器将结构作为返回传递,因此必须将其作为指针传递给堆栈上的被调用方。
问题是不良的C绑定(Microsoft标头错误)。建议采取以下修复措施:
旧代码:
D3D12_CPU_DESCRIPTOR_HANDLE (
STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )(
ID3D12DescriptorHeap * This);
用。。。来代替:
void ( STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart )(
ID3D12DescriptorHeap *This, D3D12_CPU_DESCRIPTOR_HANDLE *pOut);
谢谢。