2015-12-06 251 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); 

微軟需要排序了這一點。