2015-12-06 3 views
9

Je semble avoir trébuché sur un problème concernant la programmation de DirectX 12.0 et aucune recherche jusqu'ici n'a offert un aperçu du problème. Par conséquent, j'ai été laissé pour localiser le problème moi-même, sauf qu'il ne semble pas encore être une solution tangible.GetCPUDescriptorHandleForHeapStart corruption de la pile

Pour vous informer, je suis programmation en utilisant C (non C++) et, comme il ressort, les fichiers d'en-tête DirectX 12 fourni faire support C, aux côtés de C++, bien que le problème que je l'ai rencontré est étrange en ce sens qu'il semble mal conçu pour C, probablement en raison du fait que peu de gens programment des applications complexes (en particulier orientées objet) dans cette langue.

Ceci est mon problème: j'ai ici dans ma procédure D3D12 dispositif-initialisation du bloc de code suivant:

/* 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 signifie ' poignée à Render Target Voir' (D3D12_CPU_DESCRIPTOR_HANDLE) et pRTVHeap signifie ' Pointeur à Render Target View Tas' (ID3D12DescriptorHeap).

est ici l'équivalent du C - ceci fonctionne très bien:

/* 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(); 

Il n'y a pas d'erreur de compilation actuelle, mais lors de l'exécution, appelant cette méthode (GetCPUDescriptorHandleForHeapStart) en C déclenche une corruption de pile (ESP se dérégler par 4 octets).

j'ai examiné le démontage du procédé et pris note du RET (retour) instruction:

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 

Pour ceux qui sont familiers avec l'assemblage, ou autrement la convention d'appel __stdcall des objets COM (Object Model Component) , le pointeur 'this', transmis sur la pile, est le premier paramètre (et, dans ce cas, le seul paramètre) de la méthode, de sorte que l'objet COM peut accéder à ses propres données.

L'extrait de code suivant (montré également à la fin de l'extrait de code ci-dessus) appelle ma confusion, et à juste titre lorsque le moteur d'exécution renvoie une erreur « désaligné ESP »:

ret  8 

Un seul paramètre est d'être passé dans ce cas, qui est le pointeur "this". La taille d'un pointeur (sur un système 32 bits - mon architecture cible pour le moment est x86) est de 4 octets (32 bits), alors pourquoi l'appelé nettoie-t-il 8 octets sur la pile?

Ai-je raison de dire que c'est un bug? Microsoft a-t-il besoin d'être informé de ce problème? Ai-je tort? Est-ce une erreur stupide de ma part?

Merci pour votre temps et j'espère que quelqu'un avec plus de connaissances que moi peut m'éclairer sur le problème, mais ne suggère pas que la solution serait d'écrire en C++ au lieu de C. qu'il ne devrait pas être nécessaire et personnellement, je pense, dans mon cas, que ce serait une approche paresseuse, surtout quand je trouve que C permet un contrôle plus programmatique et (dans mon cas ici) plus d'efficacité.

+0

La même chose se produit-elle, par ex. 'GetResourceAllocationInfo' et d'autres méthodes struct-return? Dans tous les cas, vous devez modifier votre réponse et l'accepter (peut-être même obtenir le badge [self-learner] (http://stackoverflow.com/help/badges/14/self-learner) pour aider à augmenter visibilité pour [les gens du futur] (https://xkcd.com/979/). – MooseBoys

+0

Je vais enquêter. Je ne m'attendais pas à une réponse - excusez ma réponse tardive. Après avoir signalé le problème à Microsoft, j'ai reçu un accusé de réception. Je n'ai aucune idée si quelque chose est fait, ou si mon problème est considéré. Il devrait être facile à corriger car, après tout, c'est seulement le fichier d'en-tête qui doit être modifié et non l'API elle-même. Mais je vais enquêter et revenir avec mes découvertes. Je ne peux rien garantir, je suis toujours un débutant DirectX-12. –

Répondre

4

SOLUTION

Je fixe mon problème. Après le chargement des symboles de débogage pour D3D12.DLL je pourrais déterminer par les conventions de dénomination (par exemple ID3D12DescriptionHeap :: GetCPUDescriptorHandleForHeapStart, les deux-points ici sont indicatifs) que la DLL a été écrite en C++. Un deuxième paramètre (caché) est en effet transmis à la fonction - un pointeur vers la structure de sortie définie comme D3D12_CPU_DESCRIPTOR_HANDLE (qui est structurellement juste un entier, aliasé comme une structure Je ne sais pas pourquoi ils le font). J'ai oublié que C++ diffère de C en ce que C++ peut renvoyer des structures comme valeurs de retour, et que les structures ne peuvent pas être passées comme un retour via le registre EAX, il doit donc être passé comme pointeur sur la pile à l'appelé.

Microsoft devrait documenter cela !! Pas un bug, juste une mauvaise documentation! Le fichier d'en-tête ne spécifie pas (dans la méthode d'interface définie par C) cette différence!

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

devrait être:

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

Microsoft doit trier cela.