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


Связывание шейдеров эффектов

Direct2D использует оптимизацию, называемую связыванием шейдера эффектов, которая объединяет несколько этапов отрисовки графа эффектов в один проход.

Общие сведения о связывании шейдера эффектов

Оптимизация компоновки шейдеров эффектов основана на компоновке шейдеров HLSL— функции Direct3D 11.2, которая позволяет создавать пиксельные и вершинные шейдеры во время выполнения путем связывания предварительно скомпилированных функций шейдеров. На следующих рисунках показана концепция связывания шейдера эффектов в графе эффектов. На первом рисунке показан типичный граф эффектов Direct2D с четырьмя преобразованиями отрисовки. Без связывания шейдеров каждое преобразование использует проход отрисовки и требует промежуточной поверхности; в общей сложности для этого графа требуется 4 прохода и 3 промежуточных.

преобразование графа без связывания шейдера: 4 прохода и 3 промежуточных.

На втором рисунке показан тот же граф эффектов, где каждое преобразование отрисовки было заменено версией связываемой функции. Direct2D может связать весь граф и выполнить его за один проход без каких-либо промежуточных параметров. Это может значительно сократить время выполнения GPU и уменьшить пиковое потребление памяти GPU.

граф преобразования со связыванием шейдера: 1 проход, 0 промежуточных значений.

 

Связывание шейдеров эффектов работает с отдельными преобразованиями в рамках эффекта; это означает, что даже граф с одним эффектом может извлечь выгоду из связывания шейдеров, если этот эффект имеет несколько допустимых преобразований.

Использование связывания шейдера эффектов

Если вы создаете приложение Direct2D, использующее эффекты, вам не нужно ничего делать, чтобы воспользоваться преимуществами связывания шейдеров эффектов. Direct2D автоматически анализирует граф эффектов, чтобы определить наиболее оптимальный способ связывания каждого преобразования.

Авторы эффектов несут ответственность за реализацию своего эффекта таким образом, чтобы поддерживать связывание шейдеров эффектов; Дополнительные сведения см. в разделе Создание пользовательского эффекта, совместимого с шейдерами . Все встроенные эффекты поддерживают связывание шейдеров.

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

В случае, если существует такая опасность связывания, Direct2D не будет связывать преобразования, смежные с опасностью, но по-прежнему будет пытаться связать оставшуюся часть графа.

граф преобразования со связующей опасностью: 2 прохода, 1 промежуточный.

Создание пользовательского эффекта, совместимого с компоновкой шейдера

Если вы создаете собственный пользовательский эффект Direct2D, необходимо убедиться, что его преобразования поддерживают связывание шейдера эффектов. Это требует незначительных изменений по сравнению с предыдущими пользовательскими эффектами. Если преобразование в пользовательском эффекте не поддерживает связывание шейдеров, Direct2D не будет связывать его с преобразованиями, смежными с ним в графе эффекта.

Как автор пользовательских эффектов вы должны знать о нескольких ключевых понятиях и требованиях:

  • Нет изменений в реализации интерфейса

    Вам не нужно изменять код, реализуя различные интерфейсы эффектов, такие как ID2D1DrawTransform.

  • Предоставление полной и экспортной версии шейдеров

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

    Если преобразование предоставляет только полный большой двоичный объект шейдера пикселей (через ID2D1EffectContext::LoadPixelShader), он не будет связан с смежными преобразованиями.

  • Вспомогательные функции

    Direct2D предоставляет вспомогательные функции и макросы HLSL , которые автоматически создают полную и экспортную версию функции шейдера. Эти вспомогательные функции можно найти в d2d1effecthelpers.hlsli. Кроме того, компилятор HLSL (FXC) позволяет вставлять шейдер функции экспорта в частное поле в полном шейдере. Таким образом, вам нужно создать шейдер только один раз и передать обе версии в Direct2D одновременно. Как d2d1effecthelpers.hlsli, так и компилятор FXC включены в состав windows SDK.

    Вспомогательные функции:

    Вы также можете вручную создать две версии каждого шейдера и скомпилировать их дважды, если выполнены спецификации, описанные ниже в разделе Экспорт спецификаций функций .

  • Только шейдеры пикселей

    Direct2D не поддерживает связывание вычислительных или вершинных шейдеров. Однако если эффект использует как вершину, так и шейдер пикселей, выходные данные пиксельного шейдера по-прежнему можно связать.

  • Простая и сложная выборка

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

    Преобразование оттенков серого является примером простой выборки. значение конкретного выходного пикселя зависит только от значения соответствующего входного пикселя.

    Некоторые пиксельные шейдеры, например размытие гауссов, вычисляют выходные данные из нескольких входных выборок, а не только из одной выборки. Считается, что такой пиксельный шейдер выполняет сложную выборку.

    Gaussian размытие является примером сложной выборки. Значение центрального выходного пикселя зависит от нескольких входных пикселей.

    Только функции шейдера с простыми входными данными могут быть предоставлены другой функцией шейдера. Функции шейдера со сложными входными данными должны иметь входную текстуру для выборки. Это означает, что Direct2D не будет связывать шейдер со сложными входными данными со своим предшественником.

    При использовании вспомогательных средств Direct2D HLSL необходимо указать в HLSL, использует ли шейдер сложные или простые входные данные.

Пример шейдера эффектов, совместимый с компоновкой

Используя вспомогательные функции D2D, следующий фрагмент кода представляет простой шейдер эффектов, совместимый с компоновкой:

#define D2D_INPUT_COUNT 1
#define D2D_INPUT0_SIMPLE
#include “d2d1effecthelpers.hlsli”

D2D_PS_ENTRY(LinkingCompatiblePixelShader)
{
    float4 input = D2DGetInput(0);
    input.rgb *= input.a;
    return input;
}          

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

Шейдер, совместимый с компоновкой, должен предоставлять как обычный однопрохавный пиксельный шейдер, так и функцию экспортного шейдера. Макрос D2D_PS_ENTRY позволяет создавать каждый из них из одного кода при использовании в сочетании со скриптом компиляции шейдера.

При компиляции полного шейдера макросы разворачиваются в следующий код, имеющий входную сигнатуру, совместимую с D2D Effects.

Texture2D<float4> InputTexture0;
SamplerState InputSampler0;

float4 LinkingCompatiblePixelShader(
    float4 pos   : SV_POSITION,
    float4 posScene : SCENE_POSITION,
    float4 uv0  : TEXCOORD0
    ) : SV_Target
    {
        float4 input = InputTexture0.Sample(InputSampler0, uv0.xy);
        input.rgb *= input.a;
        return input;
    }    

При компиляции версии функции экспорта того же кода создается следующий код:

// Shader function version
export float4 LinkingCompatiblePixelShader_Function(
    float4 input0 : INPUT0)
    {
        input.rgb *= input.a;
        return input;
    }      

Обратите внимание, что входные данные текстуры, обычно полученные путем выборки Texture2D, были заменены входными данными функции (input0).

Полное пошаговое описание действий, необходимых для создания эффекта, совместимого с компоновкой, см. в руководстве По пользовательским эффектам и в примере настраиваемых эффектов Direct2D.

Компиляция шейдера, совместимого с компоновкой

Чтобы быть связываемым, большой двоичный объект пиксельного шейдера, передаваемый В D2D, должен содержать как полную, так и экспортную версии шейдера. Это достигается путем внедрения скомпилированной функции экспорта в область D3D_BLOB_PRIVATE_DATA.

При создании шейдеров с помощью вспомогательных функций D2D целевой объект компиляции D2D должен быть определен во время компиляции. Целевыми типами компиляции являются D2D_FULL_SHADER и D2D_FUNCTION.

Компиляция шейдера эффектов, совместимого с компоновкой, состоит из двух этапов:

Примечание

При компиляции эффекта с помощью Visual Studio необходимо создать пакетный файл, который выполняет обе команды FXC, и запустить этот пакетный файл как пользовательский шаг сборки, выполняемый перед этапом компиляции.

 

Шаг 1. Компиляция функции экспорта

fxc /T <shadermodel> <MyShaderFile>.hlsl /D D2D_FUNCTION /D D2D_ENTRY=<entry> /Fl <MyShaderFile>.fxlib           

Чтобы скомпилировать версию функции экспорта шейдера, необходимо передать следующие флаги в FXC.

Flag Описание
/T <ShaderModel> Задайте для shaderModel <> соответствующий профиль шейдера пикселей, как определено в синтаксисе FXC. Это должен быть один из профилей, перечисленных в разделе "Связывание шейдеров HLSL".
<MyShaderFile.hlsl> Задайте для MyShaderFile <> имя HLSL-файла.
/D D2D_FUNCTION Это определение предписывает FXC скомпилировать версию функции экспорта шейдера.
/D D2D_ENTRY=<entry> Задайте <для записи> имя точки входа HLSL, определенной в макросе D2D_PS_ENTRY .
/Fl <MyShaderFile.fxlib> Задайте для <MyShaderfile> значение, в котором будет храниться версия функции экспорта шейдера. Обратите внимание, что расширение .fxlib предназначено только для упрощения идентификации.

Шаг 2. Компиляция полного шейдера и внедрение функции экспорта

fxc /T ps_<shadermodel> <MyShaderFile>.hlsl /D D2D_FULL_SHADER /D D2D_ENTRY=<entry> /E <entry> /setprivate <MyShaderFile>.fxlib /Fo <MyShader>.cso /Fh <MyShader>.h           

Чтобы скомпилировать полную версию шейдера с внедренной версией экспорта, необходимо передать в FXC следующие флаги.

Flag Описание
/T <ShaderModel> Задайте для shaderModel <> соответствующий профиль шейдера пикселей, как определено в синтаксисе FXC. Это должен быть профиль шейдера пикселей, соответствующий профилю связывания, указанному на шаге 1.
<MyShaderFile.hlsl> Задайте для MyShaderFile <> имя HLSL-файла.
/D D2D_FULL_SHADER Это определение предписывает FXC скомпилировать полную версию шейдера.
/D D2D_ENTRY=<entry> Задайте <для записи> имя точки входа HLSL, определенной в макросе D2D_PS_ENTRY().
Запись /E <> Задайте <для записи> имя точки входа HLSL, определенной в макросе D2D_PS_ENTRY().
/setprivate <MyShaderFile.fxlib> Этот аргумент указывает FXC внедрить шейдер функции экспорта, созданный на шаге 1, в область D3D_BLOB_PRIVATE_DATA.
/Fo <MyShader.cso> Задайте для <MyShader> значение, в котором вы хотите сохранить окончательный комбинированный скомпилированный шейдер.
/Fh <MyShader.h> Задайте для <MyShader> значение, в котором вы хотите сохранить окончательный объединенный заголовок.

Экспорт спецификаций функций

Можно ( хотя и не рекомендуется) создать совместимый шейдер эффектов без использования предоставленных D2D вспомогательных средств. Необходимо внимательно следить за тем, чтобы входные подписи полного шейдера и функции экспорта соответствовали спецификациям D2D.

Спецификации полных шейдеров такие же, как и в более ранних версиях Windows. Вкратце, входные параметры шейдера пикселей должны быть SV_POSITION, SCENE_POSITION и один TEXCOORD для каждого входного эффекта.

Для функции экспорта функция должна возвращать значение float4, а ее входные данные должны быть одного из следующих типов:

  • Простой ввод

    float4 d2d_inputN : INPUTN         
    

    Для простых входных данных D2D либо вставляет функцию Sample между входной текстурой и функцией шейдера, либо входные данные будут предоставлены выходными данными другой функции шейдера.

  • Сложные входные данные

    float4 d2d_uvN  : TEXCOORDN                
    

    Для сложных входных данных D2D будет передавать только координату текстуры, как описано в документации по Windows 8.

  • Расположение вывода

    float4 d2d_posScene : SCENE_POSITION                
    

    Можно определить только один SCENE_POSITION входных данных. Этот параметр следует включать только при необходимости, так как только одна функция для каждого связанного шейдера может использовать этот параметр.

Семантика должна быть определена как описано выше, так как D2D проверит семантику, чтобы решить, как связать функции. Если какие-либо входные данные функции не соответствуют одному из указанных выше типов, функция будет отклонена для связывания шейдера.

Вспомогательные функции HLSL

Интерфейс ID3D11Linker

ИНТЕРФЕЙС ID3D11FunctionLinkingGraph