Compilar um efeito (Direct3D 11)

Depois que um efeito tiver sido criado, a próxima etapa é compilar o código para marcar para problemas de sintaxe.

Faça isso chamando uma das APIs de compilação (D3DX11CompileFromFile, D3DX11CompileFromMemory ou D3DX11CompileFromResource ). Essas APIs invocam o fxc.exe do compilador de efeito, que compila o código HLSL. É por isso que a sintaxe do código em um efeito se parece muito com o código HLSL. (Há algumas exceções que serão tratadas posteriormente). O compilador de efeito/compilador hlsl, fxc.exe, está disponível no SDK na pasta utilities para que os sombreadores (ou efeitos) possam ser compilados offline se você escolher. Consulte a documentação para executar o compilador na linha de comando.

Exemplo

Aqui está um exemplo de compilação de um arquivo de efeito.

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

Um parâmetro das APIs de compilação é uma interface include. Gere um deles se você quiser incluir um comportamento personalizado quando o compilador ler um arquivo de inclusão. O compilador executa esse comportamento personalizado sempre que cria ou compila um efeito (que usa o ponteiro include). Para implementar o comportamento de inclusão personalizado, derive uma classe da interface ID3DInclude . Isso fornece à sua classe dois métodos: Abrir e Fechar. Implemente o comportamento personalizado nesses métodos.

Pesquisando arquivos de inclusão

O ponteiro que o compilador passa no parâmetro pParentData para o método Open do manipulador de inclusão pode não apontar para o contêiner que inclui o arquivo #include que o compilador precisa para compilar o código do sombreador. Ou seja, o compilador pode passar NULL em pParentData. Portanto, recomendamos que o manipulador de inclusão pesquise sua própria lista de locais de inclusão para conteúdo. O manipulador de inclusão pode adicionar dinamicamente novos locais de inclusão, pois ele recebe esses locais em chamadas para seu método Open .

No exemplo a seguir, suponha que os arquivos de inclusão do código de sombreador sejam armazenados no diretório somewhereelse . Quando o compilador chama o método Open do manipulador include para abrir e ler o conteúdo de somewhereelse\foo.h, o manipulador include pode salvar o local do diretório somewhereelse . Posteriormente, quando o compilador chama o método Open do manipulador include para abrir e ler o conteúdo de bar.h, o manipulador de inclusão pode pesquisar automaticamente no diretório somewhereelse para bar.h.

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

Foo.h:
#include "bar.h"

Macros

A compilação de efeito também pode usar um ponteiro para macros definidas em outro lugar. Por exemplo, suponha que você queira modificar o efeito em BasicHLSL10 para usar duas macros: zero e uma. O código de efeito que usa as duas macros é mostrado aqui.

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

Aqui está a declaração para as duas macros.

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

As macros são uma matriz de macros terminada em NULL; em que cada macro é definida usando um struct D3D10_SHADER_MACRO .

Modifique a chamada de efeito de compilação para usar um ponteiro para as macros.

D3DX11CompileFromFile( str, Shader_Macros, NULL, pFunctionName, 
                       pProfile, D3D10_SHADER_ENABLE_STRICTNESS, NULL, 
                       NULL, &pBlob, &pErrorBlob, NULL );    

Sinalizadores de sombreador HLSL

Sinalizadores de sombreador especificam restrições de sombreador para o compilador HLSL. Esses sinalizadores afetam o código gerado pelo compilador de sombreador das seguintes maneiras:

  • Otimize o tamanho do código.
  • Incluindo informações de depuração, o que impede o controle de fluxo.
  • Afeta o destino de compilação e se um sombreador pode ser executado em hardware herdado.

Esses sinalizadores poderão ser combinados logicamente se você não tiver especificado duas características conflitantes. Para obter uma listagem dos sinalizadores , consulte Constantes D3D10_SHADER.

Sinalizadores FX

Use esses sinalizadores ao criar um efeito para definir o comportamento da compilação ou o comportamento do efeito de runtime. Para obter uma listagem dos sinalizadores , consulte Constantes D3D10_EFFECT.

Verificando erros

Se durante a compilação ocorrer um erro, a API retornará uma interface que contém os erros do compilador de efeito. Essa interface é chamada ID3DBlob. Não é diretamente legível; no entanto, retornando um ponteiro para o buffer que contém os dados (que é uma cadeia de caracteres), você pode ver quaisquer erros de compilação.

Este exemplo contém um erro no BasicHLSL.fx, a primeira declaração de variável ocorre duas vezes.

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

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

Esse erro faz com que o compilador retorne o erro a seguir, conforme mostrado na captura de tela a seguir da janela Inspeção no Microsoft Visual Studio.

captura de tela da janela watch do Visual Studio com um erro de 0x01997fb8

Como o compilador retorna o erro em um ponteiro LPVOID, converta-o em uma cadeia de caracteres na janela Inspeção.

Este é o código que retorna o erro da compilação com falha.

// 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
}

Renderizando um efeito (Direct3D 11)