Compilare un effetto (Direct3D 11)
Dopo la creazione di un effetto, il passaggio successivo consiste nel compilare il codice per verificare la presenza di problemi di sintassi.
A tale scopo, chiamare una delle API di compilazione (D3DX11CompileFromFile, D3DX11CompileFromMemoryo D3DX11CompileFromResource ). Queste API richiamano il compilatore dell'effetto fxc.exe, che compila il codice HLSL. Ecco perché la sintassi per il codice in un effetto è molto simile al codice HLSL. Alcune eccezioni verranno gestite in un secondo momento. Il compilatore dell'effetto/hlsl, fxc.exe, è disponibile nell'SDK nella cartella delle utilità in modo che gli shader (o gli effetti) possano essere compilati offline se si sceglie. Vedere la documentazione per l'esecuzione del compilatore dalla riga di comando.
- esempio di
- include
- ricerca di file di inclusione
- macro
- flag shader HLSL
- flag FX
- controllo degli errori
- argomenti correlati
Esempio
Ecco un esempio di compilazione di un file di effetto.
WCHAR str[MAX_PATH];
DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );
hr = D3DX11CompileFromFile( str, NULL, NULL, pFunctionName, pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL, NULL, &pBlob, &pErrorBlob, NULL );
Include
Un parametro delle API di compilazione è un'interfaccia di inclusione. Generare uno di questi se si desidera includere un comportamento personalizzato quando il compilatore legge un file di inclusione. Il compilatore esegue questo comportamento personalizzato ogni volta che crea o compila un effetto (che usa il puntatore di inclusione). Per implementare un comportamento di inclusione personalizzato, derivare una classe dall'interfaccia ID3DInclude. Ciò fornisce alla classe due metodi: Open e Close. Implementare il comportamento personalizzato in questi metodi.
Ricerca di file di inclusione
Il puntatore passato dal compilatore al parametro pParentData al metodo open del gestore di inclusione potrebbe non puntare al contenitore che include il file #include che il compilatore deve compilare il codice dello shader. Ciò significa che il compilatore potrebbe passare NULL in pParentData. Pertanto, è consigliabile che il gestore di inclusione cerchi il proprio elenco di posizioni di inclusione per il contenuto. Il gestore di inclusione può aggiungere dinamicamente nuove posizioni di inclusione quando riceve tali posizioni nelle chiamate al relativo metodo Open.
Nell'esempio seguente si supponga che i file di inclusione del codice shader siano entrambi archiviati nella directory da qualche parte. Quando il compilatore chiama il metodo open del gestore di inclusione per aprire e leggere il contenuto di somewhereelse\foo.h, il gestore di inclusione può salvare la posizione del da qualche parte directory. Successivamente, quando il compilatore chiama il metodo open del gestore di inclusione per aprire e leggere il contenuto di bar.h, il gestore di inclusione può cercare automaticamente nella directory da qualche parte per bar.h.
Main.hlsl:
#include "somewhereelse\foo.h"
Foo.h:
#include "bar.h"
Macro
La compilazione degli effetti può anche portare un puntatore alle macro definite altrove. Si supponga, ad esempio, di voler modificare l'effetto in BasicHLSL10, per usare due macro: zero e una. Il codice dell'effetto che usa le due macro è illustrato di seguito.
if( bAnimate )
vAnimatedPos += float4(vNormal, zero) *
(sin(g_fTime+5.5)+0.5)*5;
Output.Diffuse.a = one;
Ecco la dichiarazione per le due macro.
D3D10_SHADER_MACRO Shader_Macros[3] = { "zero", "0", "one", "1.0f", NULL, NULL };
Le macro sono una matrice di macro con terminazione NULL; dove ogni macro viene definita usando uno struct D3D10_SHADER_MACRO.
Modificare la chiamata all'effetto di compilazione per impostare un puntatore alle macro.
D3DX11CompileFromFile( str, Shader_Macros, NULL, pFunctionName,
pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL,
NULL, &pBlob, &pErrorBlob, NULL );
Flag shader HLSL
I flag shader specificano vincoli shader per il compilatore HLSL. Questi flag influiscono sul codice generato dal compilatore shader nei modi seguenti:
- Ottimizzare le dimensioni del codice.
- Inclusione delle informazioni di debug, che impedisce il controllo del flusso.
- Influisce sulla destinazione di compilazione e sul fatto che uno shader possa essere eseguito nell'hardware legacy.
Questi flag possono essere combinati logicamente se non sono state specificate due caratteristiche in conflitto. Per un elenco dei flag, vedere D3D10_SHADER Costanti.
Flag FX
Usare questi flag quando si crea un effetto per definire il comportamento di compilazione o l'effetto di runtime. Per un elenco dei flag, vedere D3D10_EFFECT Costanti.
Controllo degli errori
Se durante la compilazione si verifica un errore, l'API restituisce un'interfaccia che contiene gli errori del compilatore dell'effetto. Questa interfaccia è denominata ID3DBlob. Non è direttamente leggibile; Tuttavia, restituendo un puntatore al buffer che contiene i dati (ovvero una stringa), è possibile visualizzare eventuali errori di compilazione.
Questo esempio contiene un errore in BasicHLSL.fx, la prima dichiarazione di variabile si verifica due volte.
//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
float4 g_MaterialAmbientColor; // Material's ambient color
// Declare the same variable twice
float4 g_MaterialAmbientColor; // Material's ambient color
Questo errore fa sì che il compilatore restituisca l'errore seguente, come illustrato nella schermata seguente della finestra Espressione di controllo in Microsoft Visual Studio.
Poiché il compilatore restituisce l'errore in un puntatore LPVOID, eseguirne il cast su una stringa di caratteri nella finestra Espressione di controllo.
Ecco il codice che restituisce l'errore dalla compilazione non riuscita.
// Read the D3DX effect file
WCHAR str[MAX_PATH];
ID3DBlob* l_pBlob_Effect = NULL;
ID3DBlob* l_pBlob_Errors = NULL;
hr = DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );
hr = D3DX11CompileFromFile( str, NULL, NULL, pFunctionName,
pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL,
NULL, &pBlob, &pErrorBlob, NULL );
LPVOID l_pError = NULL;
if( pErrorBlob )
{
l_pError = pErrorBlob->GetBufferPointer();
// then cast to a char* to see it in the locals window
}
Argomenti correlati