2015-12-06 7 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 означает ' Ручка для Render Target View' (D3D12_CPU_DESCRIPTOR_HANDLE) и pRTVHeap означает ' Pointer в Render Target Просмотр Heap' (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 (Component Object Model) объекты , этот «указатель», переданный в стек, является первым параметром (и в этом случае является также единственным параметром) метода, так что COM-объект может получить доступ к своим собственным данным.

Следующий фрагмент кода (также показан в конце фрагмента кода выше) вызывает мое замешательство, и это справедливо, когда среда выполнения выдает «откалибрована ESP» ошибка:

ret  8 

только один параметр является в этом случае, который является «этим» указателем. Размер указателя (в 32-битной системе - моя целевая архитектура на данный момент - x86) - 4 байта (32 бита), так почему вызывающая сторона очищает 8 байтов в стеке?

Могу ли я назвать это ошибкой? Необходимо ли информировать Microsoft об этой проблеме? Я ошибаюсь? Это глупая ошибка с моей стороны?

Спасибо за ваше время, и я надеюсь, что кто-нибудь, у кого больше знаний, чем я, может рассказать мне об этом, но, пожалуйста, не предлагайте, чтобы решение заключалось в написании на C++ вместо C. Я уже рассмотрел это и сделал вывод что это не обязательно, и лично я чувствую, в моем случае, что это был бы ленивый подход к решению, особенно когда я нахожу, что C позволяет более программному управлению и (в моем случае здесь) повысить эффективность.

+0

Выполняется то же самое, например. 'GetResourceAllocationInfo' и другие методы преобразования структуры? В любом случае, вы должны сделать свое редактирование ответом и принять его (возможно, даже получить значок [self-learner] (http://stackoverflow.com/help/badges/14/self-learner)), чтобы помочь увеличить видимость для [людей из будущего] (https://xkcd.com/979/). – MooseBoys

+0

Я буду исследовать. Я не ожидал ответа - извините мой поздний ответ. Сообщив о проблеме Microsoft, я получил подтверждение. Я понятия не имею, что-то делается, или рассматривается ли моя проблема. Это должно быть легко исправить, потому что, в конце концов, это только файл заголовка, который нуждается в модификации, а не сам API. Но я буду исследовать и возвращаться с моими открытиями. Я ничего не могу гарантировать, но я все еще новичок в DirectX-12. –

ответ

4

РЕШЕНИЕ

Я установил свою собственную проблему. После загрузки символов отладки для D3D12.DLL я мог бы определить по соглашениям об именах (например, ID3D12DescriptionHeap :: GetCPUDescriptorHandleForHeapStart, здесь показаны два двоеточия), которые DLL была написана на C++. A (скрытый) второй параметр действительно передается функции - указатель на структуру вывода, определенную как D3D12_CPU_DESCRIPTOR_HANDLE (которая является структурно просто целой, с псевдонимом как структура. Я не знаю, почему они это делают). Я забыл, что C++ отличается от C тем, что C++ может возвращать структуры как возвращаемые значения и что структуры не могут быть переданы в качестве возврата через регистр EAX, поэтому он должен быть передан в качестве указателя на стек для вызываемого.

Microsoft должна документировать это! Не ошибка, просто плохая документация! Файл заголовка не указывает (в методе интерфейса C) эту разницу!

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

Должно быть:

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

Microsoft должен разобраться в этом.