2015-12-06 44 views
9

Mi sembra di essere incappato in un problema relativo alla programmazione di DirectX 12.0 e nessuna ricerca finora ha offerto informazioni sul problema. Quindi sono stato lasciato a localizzare il problema da solo, tranne che non sembra ancora esserci una soluzione tangibile.GetCPUDescriptorHandleForHeapStart corruzione dello stack

Per informare voi, io sto programmazione con C (non C++) e, come è evidente, i file di intestazione DirectX 12 a condizione fare sostegno C, insieme a C++, anche se il problema che ho incontrato è strano in quanto sembra mal progettato per C, probabilmente a causa del fatto che non molte persone programmano applicazioni complesse (in particolare orientate agli oggetti) in quella lingua.

Questo è il mio problema: ho qui nella mia procedura D3D12 dispositivo-inizializzazione il seguente blocco di codice:

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

Dove hRTV sta per ' Maniglia a rendering target View' (D3D12_CPU_DESCRIPTOR_HANDLE) e pRTVHeap sta per ' Puntatore a Render Target View Heap' (ID3D12DescriptorHeap).

Ecco C++ equivalente - questo funziona bene:

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

non ci sono errori di compilazione presente, ma in fase di esecuzione, chiamata a questo metodo (GetCPUDescriptorHandleForHeapStart) in C innesca un danneggiamento di stack (ESP non essere allineate con 4 byte).

ho esaminato lo smontaggio per il metodo e reso nota del RET (ritorno) istruzione:

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 

Per coloro che hanno familiarità con il montaggio, o altrimenti il ​​__stdcall convenzione di chiamata di COM (Component Object Model) oggetti , il puntatore "this", passato sullo stack, è il primo parametro (e, in questo caso, è anche l'unico parametro) del metodo in modo che l'oggetto COM possa accedere ai propri dati.

Il seguente frammento di codice (anche mostrato alla fine del frammento di codice di cui sopra) invoca la mia confusione, ed è giusto così, quando il runtime genera un errore di 'disallineato ESP':

ret  8 

un solo parametro è di essere passato in questo caso, che è il "questo" puntatore. La dimensione di un puntatore (su un sistema a 32 bit - la mia architettura di destinazione al momento è x86) è 4 byte (32 bit), quindi perché il callee ripulisce 8 byte nello stack?

Ho ragione di chiamare questo bug? Microsoft deve essere informato di questo problema? Ho sbagliato? È un errore stupido da parte mia?

Grazie per il vostro tempo e spero che chiunque con più conoscenza di me possa illuminarmi sul problema, ma per favore non suggerire che la soluzione sarebbe scrivere in C++ anziché C. Ho già preso in considerazione questo e concluso che non dovrebbe essere necessario e personalmente ritengo, nel mio caso, che quello sarebbe un approccio pigro alla soluzione, specialmente quando trovo che C consente un controllo più programmatico e (nel mio caso qui) più efficienza.

+0

La stessa cosa accade per es. 'GetResourceAllocationInfo' e altri metodi di restituzione della struttura? In ogni caso, dovresti apportare una modifica alla tua risposta e accettarla (magari anche ottenere il distintivo [autodidatta] (http://stackoverflow.com/help/badges/14/self-learner) per contribuire ad aumentare visibilità per [persone dal futuro] (https://xkcd.com/979/). – MooseBoys

+0

Io indagherò. Non mi aspettavo una risposta - scusa la mia risposta in ritardo. Dopo aver segnalato il problema a Microsoft, ho ricevuto una conferma. Non ho idea se si sta facendo qualcosa, o se il mio problema è stato preso in considerazione. Dovrebbe essere facile da correggere perché, dopo tutto, è solo il file di intestazione che richiede modifiche e non l'API stessa. Ma indagherò e tornerò con le mie scoperte. Non posso garantire nulla, sono ancora un principiante di DirectX-12. –

risposta

4

SOLUZIONE

ho risolto il mio problema. Dopo aver caricato i simboli di debug per D3D12.DLL, ho potuto determinare le convenzioni di denominazione (ad esempio ID3D12DescriptionHeap :: GetCPUDescriptorHandleForHeapStart, i due doppi sono indicativi) che la DLL è stata scritta in C++. Un secondo parametro (nascosto) viene effettivamente passato alla funzione - un puntatore alla struttura di output definita come D3D12_CPU_DESCRIPTOR_HANDLE (che è strutturalmente solo un numero intero, alias come struttura. Non so perché lo facciano). Ho dimenticato che C++ differisce da C in quanto C++ può restituire le strutture come valori di ritorno e che le strutture non possono essere passate come un ritorno tramite il registro EAX, quindi deve essere passato come un puntatore nello stack al destinatario.

Microsoft dovrebbe documentare questo !! Non è un bug, solo una documentazione scarsa! Il file di intestazione non specifica (nel metodo dell'interfaccia definita da C) questa differenza!

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

dovrebbe essere:

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

Microsoft ha bisogno di risolvere la questione.