Поделиться через


Компиляция эффекта (Direct3D 11)

После создания эффекта следующим шагом является компиляция кода для проверка для синтаксических проблем.

Для этого вызывается один из API компиляции (D3DX11CompileFromFile, D3DX11CompileFromMemory или D3DX11CompileFromResource ). Эти API вызывают компилятор эффекта fxc.exe, который компилирует код HLSL. Именно поэтому синтаксис кода в эффекте очень похож на код HLSL. (Есть несколько исключений, которые будут обработаны позже. Компилятор эффектов или компилятор hlsl, fxc.exe, доступен в пакете SDK в папке служебных программ, чтобы при желании шейдеры (или эффекты) можно было скомпилировать в автономном режиме. См. документацию по запуску компилятора из командной строки.

Пример

Ниже приведен пример компиляции файла эффекта.

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

Одним из параметров API компиляции является интерфейс включения. Создайте один из них, если вы хотите включить настраиваемое поведение, когда компилятор считывает включаемый файл. Компилятор выполняет это пользовательское поведение каждый раз при создании или компиляции эффекта (который использует указатель включения). Чтобы реализовать настраиваемое поведение включения, наследуйте класс из интерфейса ID3DInclude . Это предоставляет классу два метода: Open и Close. Реализуйте пользовательское поведение в этих методах.

Поиск включаемого файла

Указатель, который компилятор передает в параметре pParentDataметоду Open обработчика включения, может не указывать на контейнер, содержащий файл #include, необходимый компилятору для компиляции кода шейдера. То есть компилятор может передать значение NULL в pParentData. Поэтому рекомендуется, чтобы обработчик включения искал содержимое в собственном списке включаемых расположений. Обработчик включения может динамически добавлять новые расположения включения, так как он получает эти расположения в вызовах метода Open .

В следующем примере предположим, что включаемые файлы кода шейдера хранятся в каталоге somewhereelse . Когда компилятор вызывает метод Open обработчика включения для открытия и чтения содержимого файла somewhereelse\foo.h, обработчик включения может сохранить расположение каталога somewhereelse . Позже, когда компилятор вызывает метод Open обработчика включения для открытия и чтения содержимого bar.h, обработчик включения может автоматически выполнять поиск bar.h в каталоге somewhereelse.

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

Foo.h:
#include "bar.h"

Макросы

Компиляция эффектов также может принимать указатель на макросы, определенные в другом месте. Например, предположим, что вы хотите изменить эффект в BasicHLSL10, чтобы использовать два макроса: ноль и один. Код эффекта, использующий два макроса, показан здесь.

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

Ниже приведено объявление для двух макросов.

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

Макросы представляют собой массив макросов, завершающийся значением NULL; где каждый макрос определяется с помощью структуры D3D10_SHADER_MACRO .

Измените вызов эффекта компиляции, чтобы принять указатель на макросы.

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

Флаги шейдера HLSL

Флаги шейдера указывают ограничения шейдера для компилятора HLSL. Эти флаги влияют на код, созданный компилятором шейдера, следующим образом:

  • Оптимизируйте размер кода.
  • Включение отладочной информации, которая препятствует управлению потоком.
  • Влияет на целевой объект компиляции и на то, может ли шейдер выполняться на устаревшем оборудовании.

Эти флаги можно логически объединить, если вы не указали две конфликтующие характеристики. Список флагов см. в разделе константы D3D10_SHADER.

Флаги FX

Используйте эти флаги при создании эффекта для определения поведения компиляции или эффекта среды выполнения. Список флагов см. в разделе константы D3D10_EFFECT.

Проверка ошибок

Если во время компиляции возникает ошибка, API возвращает интерфейс, содержащий ошибки компилятора эффекта. Этот интерфейс называется ID3DBlob. Он недоступен для чтения напрямую; Однако, возвращая указатель на буфер, содержащий данные (который является строкой), можно увидеть любые ошибки компиляции.

Этот пример содержит ошибку в BasicHLSL.fx, первое объявление переменной происходит дважды.

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

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

Эта ошибка приводит к тому, что компилятор возвращает следующую ошибку, как показано на следующем снимке экрана окна контрольных значений в Microsoft Visual Studio.

Снимок экрана: окно watch Visual Studio с ошибкой 0x01997fb8

Так как компилятор возвращает ошибку в указателе LPVOID, приведите ее к строке символов в окне Контрольные значения.

Ниже приведен код, который возвращает ошибку из неудачной компиляции.

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

Отрисовка эффекта (Direct3D 11)