Повреждение стека GetCPUDescriptorHandleForHeapStart

Кажется, я наткнулся на проблему, связанную с программированием на 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 выступает заУказатель в Render Target View 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 (объектная модель компонентов), указатель ‘this’, передаваемый в стек, является первым параметром (и, в данном случае, также единственным параметром) метод, чтобы COM-объект мог обращаться к своим собственным данным.

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

 ret        8

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

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

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

9

Решение

РЕШЕНИЕ

Я исправил свою проблему. После загрузки отладочных символов для D3D12.DLL я мог определить по соглашениям об именах (например, ID3D12DescriptionHeap :: GetCPUDescriptorHandleForHeapStart, здесь указываются двойные двоеточия), что DLL была написана на C ++. Второй (скрытый) параметр действительно передается в функцию — указатель на выходную структуру, определенную как 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 должна разобраться с этим.

4

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]