Compile an Effect (Direct3D 10)

Once an effect has been authored, the first step is to compile the code to check for syntax problems. This is done by calling one of the compile APIs (like D3DX10CompileEffectFromFile, D3DX10CompileEffectFromResource, D3DX10CompileEffectFromMemory). These API's invoke the effect compiler fxc.exe which is the compiler used to compile HLSL code. This is why the syntax for code in an effect looks very much like HLSL code (there are a few exceptions that will be handled later). By the way, the effect compiler/hlsl compiler (fxc.exe) is in the SDK in the utilities folder so that you can compile your shaders (or effects) offline if you choose. See the documentation for running the compiler from the command line.

Here's an example of compiling an effect file (from the BasicHLSL10 sample).

WCHAR str[MAX_PATH];
DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );

hr = D3DX10CompileEffectFromFile( str, NULL, NULL, "fx_4_0", 
    D3D10_SHADER_ENABLE_STRICTNESS, 0, pd3dDevice, NULL, NULL, 
    &l_pBlob_Effect, &l_pBlob_Errors, NULL );

Includes

One parameter is an include interface. Generate one of these if you want to include a customized behavior when reading an include file. This custom behavior is executed each time an effect (that uses the include pointer) is created or when an effect (that uses the include pointer) is compiled. To implement customized include behavior, derive a class from the Include interface. This provides your class two methods: Open and Close. Implement the custom behavior in the Open and Close methods.

Macros

Effect compilation can also take a pointer to macros that are defined elsewhere. For example, suppose you were to modify the effect in BasicHLSL10, to use two macros: zero and one. The effect code that uses the two macros is shown here.

if( bAnimate )
    vAnimatedPos += float4(vNormal, zero) *  
        (sin(g_fTime+5.5)+0.5)*5;
        
    Output.Diffuse.a = one;         

Here is the declaration for the two macros.

D3D_SHADER_MACRO Shader_Macros[3] = { "zero", "0", "one", "1.0f", NULL, NULL };

The macros are a NULL terminated array of macros; where each macro is defined with a D3D_SHADER_MACRO struct.

Lastly, modify the compile effect call to take a pointer to the macros.

D3DX10CreateEffectFromFile( str, Shader_Macros, NULL, 
    D3D10_SHADER_ENABLE_STRICTNESS, 0, pd3dDevice, NULL, NULL, 
    &g_pEffect10, NULL );

HLSL Shader Flags

Shader flags specify shader constraints to the HLSL compiler. These flags impact the code generated by the shader compiler including:

  • Size considerations: optimize the code.
  • Debug considerations: including debug information, preventing flow control.
  • Hardware considerations: the compile target and whether or not a shader can run on legacy hardware.

In general, these flags can be logically combined, assuming you have not specified two conflicting characteristics. For a listing of the flags see Effect Constants (Direct3D 10).

FX Flags

These flags used when creating an effect to define either compilation behavior or runtime effect behavior. For a listing of the flags see Effect Constants (Direct3D 10).

Checking Errors

If during compilation, an error occurs, the API returns an interface which contains the errors returned from the effect compiler. This interface is called ID3D10Blob. It is not directly readable, however, by returning a pointer to the buffer that contains the data (which is a string), you can see any compilation errors.

In this example, an error was introduced into the BasicHLSL.fx effect by copying the first variable declaration twice.

//-------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------
float4 g_MaterialAmbientColor;      // Material's ambient color

// Declare the same variable twice
float4 g_MaterialAmbientColor;      // Material's ambient color

This error caused the compiler to return the following error, as shown in the following screen shot of the watch window in Microsoft Visual Studio.

screen shot of the visual studio watch window

Since the error is returned in a LPVOID pointer, cast it to a character string in the watch window.

Here is the code used to return the error from the failed compile.

// Read the D3DX effect file
WCHAR str[MAX_PATH];
ID3D10Blob* l_pBlob_Effect = NULL;
ID3D10Blob* l_pBlob_Errors = NULL;
hr = DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"BasicHLSL10.fx" );
hr = D3DX10CompileEffectFromFile( str, NULL, NULL, 
    D3D10_SHADER_ENABLE_STRICTNESS, 0, NULL, 
    &l_pBlob_Effect, &l_pBlob_Errors );

LPVOID l_pError = NULL;
if( l_pBlob_Errors )
{
    l_pError = l_pBlob_Errors->GetBufferPointer();
    // then cast to a char* to see it in the locals window
}

Rendering an Effect (Direct3D 10)