Condividi tramite


Compilare un effetto (Direct3D 11)

Dopo aver creato 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, D3DX11CompileFromMemory o 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. Sono presenti alcune eccezioni che verranno gestite in un secondo momento. Il compilatore dell'effetto/compilatore hlsl, fxc.exe, è disponibile nell'SDK nella cartella 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

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

Includes

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 . In questo modo la classe include due metodi: Open e Close. Implementare il comportamento personalizzato in questi metodi.

Ricerca di file di inclusione

Il puntatore che il compilatore passa il 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. Ovvero, il compilatore potrebbe passare NULL in pParentData. È quindi consigliabile che il gestore di inclusione cerchi il proprio elenco di percorsi 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 il percorso della directory in qualche posizione. 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ò eseguire automaticamente la ricerca nella directory in qualche posizione per bar.h.

Main.hlsl:
#include "somewhereelse\foo.h"

Foo.h:
#include "bar.h"

Macro

La compilazione dell'effetto 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 uno. 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 utilizzando uno struct D3D10_SHADER_MACRO .

Modificare la chiamata dell'effetto di compilazione per portare 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.
  • Incluse le informazioni di debug, che impediscono il controllo del flusso.
  • Influisce sulla destinazione di compilazione e sul fatto che uno shader possa essere eseguito su hardware legacy.

Questi flag possono essere combinati logicamente se non sono state specificate due caratteristiche in conflitto. Per un elenco dei flag, vedere costanti D3D10_SHADER.

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 viene eseguita 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 Espressioni di controllo in Microsoft Visual Studio.

screenshot della finestra di watch di Visual Studio con un errore di 0x01997fb8

Poiché il compilatore restituisce l'errore in un puntatore LPVOID, eseguirne il cast in 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
}

Rendering di un effetto (Direct3D 11)