在使用DirectX 12.0进行编程时,我偶然发现了一个相当不寻常的问题。到目前为止,没有任何研究具有洞察力。
我正在使用C(而不是C ++)进行编程。看起来官方的DirectX 12标头支持C和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的古老论点。
答案 0 :(得分:4)
<强>解强>
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);
谢谢。