2015-12-06 211 views
9

我似乎偶然发现了有关DirectX 12.0编程的问题,迄今为止还没有任何研究提供了有关该问题的深入见解。因此,我自己一直在寻找这个问题,但似乎还没有一个切实的解决方案。GetCPUDescriptorHandleForHeapStart堆栈损坏

要告诉你,我现在用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(); 

有没有编译时错误存在,但在运行时,调用此方法(GetCPUDescriptorHandleForHeapStart c)中触发堆栈腐败(由ESP变得不对齐4字节)。

我检查了拆卸的方法并提出注意RET(返回)指令的:

50290030 mov   edi,edi 
50290032 push  ebp 
50290033 mov   ebp,esp 
50290035 mov   ecx,dword ptr [ebp+8] 
50290038 mov   eax,dword ptr [ecx+2Ch] 
5029003B cmp   dword ptr [eax],2 
5029003E jne   5029004A 
50290040 mov   eax,dword ptr [ebp+0Ch] 
50290043 mov   ecx,dword ptr [ecx+28h] 
50290046 mov   dword ptr [eax],ecx 
50290048 jmp   50290055 
5029004A push  dword ptr [ebp+0Ch] 
5029004D call  5029005E 
50290052 mov   eax,dword ptr [ebp+0Ch] 
50290055 pop   ebp 
50290056 ret   8 

对于那些熟悉汇编,或以其他方式__stdcall调用COM(组件对象模型)的约定对象,在栈上传递的'this'指针是方法的第一个参数(在本例中也是唯一的参数),以便COM对象可以访问它自己的数据。

下面的代码段(也在上面的代码段的端部示出)调用我的混淆,这是理所当然的,当运行时将引发一个“错位ESP”错误:

ret  8 

只有一个参数是被在这种情况下,这是'this'指针。指针的大小(在32位系统上 - 目前我的目标架构是x86)是4字节(32位),那么为什么被调用者要清除堆栈中的8个字节?

我可以称之为错误吗?微软是否需要被告知这个问题?我错了吗?这是我的一个愚蠢的错误?

谢谢你的时间,我希望有比我更多知识的人可以在这个问题上给我启发,但请不要建议解决方案是用C++而不是C写。我已经考虑过这一点,并得出结论在我看来,这不应该是必要的,我个人觉得这将是一种懒惰的解决方案,特别是当我发现C允许更多的程序控制和更高的效率(在我的情况下)。

+0

同样的事情发生在例如'GetResourceAllocationInfo'和其他结构返回方法?无论如何,你应该让你的编辑成为答案并接受它(甚至可以获得[自学者]徽章(http://stackoverflow.com/help/badges/14/self-learner)徽章以帮助增加[来自未来的人]的可见度(https://xkcd.com/979/)。 – MooseBoys

+0

我将进行调查。我没有期待答复 - 请原谅我迟到的回应。 向微软报告问题后,我收到了确认。我不知道是否有任何事情正在进行,或者我的问题是否正在考虑之中。它应该很容易修复,因为毕竟它只是需要修改的头文件而不是API本身。 但我会调查,并与我的发现回报。我无法保证任何东西,我仍然是一个DirectX-12新手。 –

回答

4

SOLUTION

我固定我自己的问题。加载D3D12.DLL的调试符号后,我可以通过命名约定(例如,ID3D12DescriptionHeap :: GetCPUDescriptorHandleForHeapStart,这里的双冒号表示该DLL是用C++编写的)。一个(隐藏的)第二个参数确实被传递给函数 - 一个指向输出结构的指针,定义为D3D12_CPU_DESCRIPTOR_HANDLE(结构上只是一个整数,别名为结构,我不知道他们为什么这么做)。我忘记了C++与C不同之处在于C++可以将结构作为返回值返回,并且该结构不能作为EAX寄存器的返回值传递,所以它必须作为堆栈中的指针传递给被调用者。

微软应该记录这个!不是一个错误,只是糟糕的文档!头文件没有指定(在C定义的接口方法中)这种差异!

D3D12_CPU_DESCRIPTOR_HANDLE (
    STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart)( 
    ID3D12DescriptorHeap * This); 

应该是:

void (STDMETHODCALLTYPE *GetCPUDescriptorHandleForHeapStart)(
    ID3D12DescriptorHeap *This, D3D12_CPU_DESCRIPTOR_HANDLE *pOut); 

微软需要排序了这一点。