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


Сравнение конвейера шейдера OpenGL ES 2.0 с Direct3D

Важные API

Концептуально конвейер шейдера Direct3D 11 очень похож на конвейер шейдера OpenGL ES 2.0. Однако с точки зрения проектирования API основные компоненты для создания этапов шейдера и управления ими являются частями двух основных интерфейсов, ID3D11Device1 и ID3D11DeviceContext1. В этом разделе рассматривается сопоставление распространенных шаблонов API конвейера шейдера OpenGL ES 2.0 с эквивалентами Direct3D 11 в этих интерфейсах.

Просмотр конвейера шейдера Direct3D 11

Объекты шейдера создаются с помощью методов в интерфейсе ID3D11Device1, например ID3D11Device1::CreateVertexShader и ID3D11Device1::CreatePixelShader.

Графический конвейер Direct3D 11 управляется экземплярами интерфейса ID3D11DeviceContext1 и имеет следующие этапы:

  • Этап входных сборок. Этап входного сборщика предоставляет данные (треугольники, линии и точки) конвейеру. Методы ID3D11DeviceContext1 , поддерживающие этот этап, префиксируются с помощью метода IA.
  • Этап вершин-шейдера — этап вершинного шейдера обрабатывает вершины, обычно выполняя такие операции, как преобразования, скининг и освещение. Шейдер вершин всегда принимает одну входную вершину и создает одну выходную вершину. Методы ID3D11DeviceContext1 , поддерживающие этот этап, префиксируются с помощью VS.
  • Этап потокового вывода — этап потокового вывода передает примитивные данные из конвейера в память на пути к растризатору. Данные можно передавать в растризатор и (или) передавать в растризатор. Данные, исходящие в память, могут быть повторно возвращены в конвейер в виде входных данных или обратного чтения из ЦП. Методы ID3D11DeviceContext1 , поддерживающие этот этап, префиксируются с помощью SO.
  • Этап расстеризатора — растризатор клипов примитивы, подготавливает примитивы для шейдера пикселей и определяет, как вызывать шейдеры пикселей. Вы можете отключить растеризацию, сказав конвейеру, что нет шейдера пикселей (присвойте шейдеру пикселей значение NULL с идентификатором ID3D11DeviceContext::P SSetShader), а также отключив проверку глубины и наборов элементов (задайте для DepthEnable и StencilEnable значение FALSE в D3D11_DEPTH_STENCIL_DESC). При отключении счетчики конвейера, связанные с растеризацией, не будут обновляться.
  • Этап шейдера пикселей — этап шейдера пикселей получает интерполированные данные для примитива и создает данные на пиксель, такие как цвет. Методы ID3D11DeviceContext1 , поддерживающие этот этап, префиксируются с помощью PS.
  • Этап слияния выходных данных — этап слияния выходных данных объединяет различные типы выходных данных (значения шейдера пикселей, глубину и набор данных) с содержимым целевого объекта визуализации и буферов глубины и набора элементов для создания окончательного результата конвейера. Методы ID3D11DeviceContext1 , поддерживающие этот этап, префиксируются с помощью OM.

(Существуют также этапы геометрических шейдеров, шейдеров корпусов, тессели и шейдеров доменов, но так как они не имеют аналогов в OpenGL ES 2.0, мы не будем обсуждать их здесь.) Полный список методов для этих этапов см. на справочных страницах ID3D11DeviceContext и ID3D11DeviceContext1. ID3D11DeviceContext1 расширяет id3D11DeviceContext для Direct3D 11.

Создание шейдера

В Direct3D ресурсы шейдеров не создаются перед компиляцией и загрузкой; вместо этого ресурс создается при загрузке HLSLis. Таким образом, нет прямой аналогии функции glCreateShader, которая создает инициализированный ресурс шейдера определенного типа (например, GL_VERTEX_SHADER или GL_FRAGMENT_SHADER). Скорее, шейдеры создаются после загрузки HLSL с определенными функциями, такими как ID3D11Device1::CreateVertexShader и ID3D11Device1::CreatePixelShader, и которые принимают тип и скомпилированный HLSL в качестве параметров.

OpenGL ES 2.0 Direct3D 11
glCreateShader Вызов ID3D11Device1::CreateVertexShader и ID3D11Device1::CreatePixelShader после успешной загрузки скомпилированного объекта шейдера, передавая их CSO в качестве буфера.

 

Компиляция шейдера

Шейдеры Direct3D должны быть предварительно компилированы как файлы скомпилированных объектов шейдеров (CSO) в приложениях универсальная платформа Windows (UWP) и загружены с помощью одного из API-интерфейсов файлов среда выполнения Windows. (Классические приложения могут компилировать шейдеры из текстовых файлов или строк во время выполнения.) Файлы CSO создаются из любых hlsl-файлов, входящих в проект Microsoft Visual Studio, и сохраняют те же имена только с расширением CSO.cso. Убедитесь, что они включены в пакет при отправке!

OpenGL ES 2.0 Direct3D 11
glCompileShader Недоступно Скомпилируйте шейдеры в CSO-файлы в Visual Studio и включите их в пакет.
Использование glGetShaderiv для состояния компиляции Недоступно Просмотрите выходные данные компиляции компилятора FX (FXC) Visual Studio, если в компиляции возникают ошибки. Если компиляция выполнена успешно, создается соответствующий CSO-файл.

 

Загрузка шейдера

Как отмечалось в разделе о создании шейдера, Direct3D 11 создает шейдер, когда соответствующий файл CSO загружается в буфер и передается одному из методов в следующей таблице.

OpenGL ES 2.0 Direct3D 11
ШейдерSource Вызов ID3D11Device1::CreateVertexShader и ID3D11Device1::CreatePixelShader после успешной загрузки скомпилированного объекта шейдера.

 

Установка конвейера

OpenGL ES 2.0 имеет объект "шейдер программы", содержащий несколько шейдеров для выполнения. Отдельные шейдеры присоединяются к объекту программы шейдера. Однако в Direct3D 11 вы работаете с контекстом отрисовки (ID3D11DeviceContext1) и создаете на нем шейдеры.

OpenGL ES 2.0 Direct3D 11
glCreateProgram Недоступно Direct3D 11 не использует абстракции объекта программы шейдера.
glLinkProgram Недоступно Direct3D 11 не использует абстракции объекта программы шейдера.
glUseProgram Недоступно Direct3D 11 не использует абстракции объекта программы шейдера.
glGetProgramiv Используйте ссылку, созданную для ID3D11DeviceContext1.

 

Создайте экземпляр ID3D11DeviceContext1 и ID3D11Device1 с помощью статического метода D3D11CreateDevice.

Microsoft::WRL::ComPtr<ID3D11Device1>          m_d3dDevice;
Microsoft::WRL::ComPtr<ID3D11DeviceContext1>  m_d3dContext;

// ...

D3D11CreateDevice(
  nullptr, // Specify nullptr to use the default adapter.
  D3D_DRIVER_TYPE_HARDWARE,
  nullptr,
  creationFlags, // Set set debug and Direct2D compatibility flags.
  featureLevels, // List of feature levels this app can support.
  ARRAYSIZE(featureLevels),
  D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for UWP apps.
  &device, // Returns the Direct3D device created.
  &m_featureLevel, // Returns feature level of device created.
  &m_d3dContext // Returns the device's immediate context.
);

Настройка портов представления

Настройка окна просмотра в Direct3D 11 очень похожа на настройку окна просмотра в OpenGL ES 2.0. В Direct3D 11 вызовите ID3D11DeviceContext::RSSetViewports с настроенным CD3D11_VIEWPORT.

Direct3D 11: настройка окна просмотра.

CD3D11_VIEWPORT viewport(
        0.0f,
        0.0f,
        m_d3dRenderTargetSize.Width,
        m_d3dRenderTargetSize.Height
        );
m_d3dContext->RSSetViewports(1, &viewport);
OpenGL ES 2.0 Direct3D 11
glViewport CD3D11_VIEWPORT, ID3D11DeviceContext::RSSetViewports

 

Настройка шейдеров вершин

Настройка шейдера вершин в Direct3D 11 выполняется при загрузке шейдера. Униформы передаются в качестве буферов констант с помощью ID3D11DeviceContext1::VSSetConstantBuffers1.

OpenGL ES 2.0 Direct3D 11
glAttachShader ID3D11Device1::CreateVertexShader
glGetShaderiv, glGetShaderSource ID3D11DeviceContext1::VSGetShader
glGetUniformfv, glGetUniformiv ID3D11DeviceContext1::VSGetConstantBuffers1.

 

Настройка шейдеров пикселей

Настройка шейдера пикселей в Direct3D 11 выполняется при загрузке шейдера. Униформы передаются в качестве буферов констант с помощью ID3D11DeviceContext1::P SSetConstantBuffers1.

OpenGL ES 2.0 Direct3D 11
glAttachShader ID3D11Device1::CreatePixelShader
glGetShaderiv, glGetShaderSource ID3D11DeviceContext1::P SGetShader
glGetUniformfv, glGetUniformiv ID3D11DeviceContext1::P SGetConstantBuffers1.

 

Создание окончательных результатов

После завершения конвейера результаты этапов шейдера извлекают в буфер назад. В Direct3D 11 так же, как и в Open GL ES 2.0, это включает вызов команды рисования для вывода результатов в виде цветовой карты в буфере заднего, а затем отправки этого обратного буфера на экран.

OpenGL ES 2.0 Direct3D 11
glDrawElements ID3D11DeviceContext1::D raw, ID3D11DeviceContext1::D rawIndexed (или другие методы Draw* в ID3D11DeviceContext1).
eglSwapBuffers IDXGISwapChain1::P resent1

 

Перенос GLSL в HLSL

GLSL и HLSL не отличаются от поддержки сложных типов и синтаксиса некоторых общих синтаксисов. Многие разработчики находят его проще всего перенести между двумя путем псевдонима общих инструкций и определений OpenGL ES 2.0 в эквивалент HLSL. Обратите внимание, что Direct3D использует версию модели шейдера для выражения набора функций HLSL, поддерживаемого графическим интерфейсом; OpenGL имеет другую спецификацию версии для HLSL. В следующей таблице показано, как получить приблизительное представление о наборах функций языка шейдера, определенных для Direct3D 11 и OpenGL ES 2.0 с точки зрения другой версии.

Язык шейдера Версия функции GLSL Модель шейдера Direct3D
Direct3D 11 HLSL ~4.30. SM 5.0
GLSL ES для OpenGL ES 2.0 1.40. Старые реализации GLSL ES для OpenGL ES 2.0 могут использовать 1.10 до 1.30. Проверьте исходный код с помощью glGetString(GL_SHADING_LANGUAGE_VERSION) или glGetString(SHADING_LANGUAGE_VERSION), чтобы определить его. ~SM 2.0

 

Дополнительные сведения о различиях между двумя языками шейдеров, а также общими сопоставлениями синтаксиса см . в справочнике GLSL -to-HLSL.

Перенос встроенных функций OpenGL в семантику HLSL

Семантика Direct3D 11 HLSL — это строки, такие как универсальное или имя атрибута, используются для идентификации значения, передаваемого между приложением и программой шейдера. Хотя они могут быть любой из различных возможных строк, рекомендуется использовать строку, например POSITION или COLOR, которая указывает на использование. Эти семантики назначаются при создании буфера констант или макета входных данных буфера. Можно также добавить число от 0 до 7 к семантике, чтобы использовать отдельные регистры для аналогичных значений. Например: COLOR0, COLOR1, COLOR2...

Семантики, которые префиксируются с помощью "SV_", являются системными семантиками, записанными в программу шейдера; Само приложение (работающее на ЦП) не может изменять их. Как правило, они содержат значения, которые являются входными или выходными данными из другого этапа шейдера в графическом конвейере или создаются полностью GPU.

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

Ниже приведены несколько сопоставлений для распространенных встроенных шейдеров OpenGL ES 2.0:

Системное значение OpenGL Используйте эту семантику HLSL
gl_Position POSITION(n) для данных буфера вершин. SV_POSITION предоставляет положение пикселя для шейдера пикселей и не может быть записано приложением.
gl_Normal NORMAL(n) для обычных данных, предоставляемых буфером вершин.
gl_TexCoord[n] TEXCOORD(n) для текстуры UV (ST в некоторых документах OpenGL) координаты, предоставленные шейдеру.
gl_FragColor COLOR(n) для данных цвета RGBA, предоставленных шейдеру. Обратите внимание, что она обрабатывается одинаково с данными координат; Семантика просто помогает определить, что это цветовые данные.
gl_FragData[n] SV_Target[n] для записи из шейдера пикселей в целевую текстуру или другой буфер пикселей.

 

Метод, с помощью которого вы кодируете семантику, не совпадает с использованием встроенных функций в OpenGL ES 2.0. В OpenGL можно получить доступ ко многим встроенным компонентам напрямую без какой-либо конфигурации или объявления; в Direct3D необходимо объявить поле в определенном буфере констант для использования определенной семантики или объявить его в качестве возвращаемого значения для метода main() шейдера.

Ниже приведен пример семантики, используемой в определении буфера констант:

struct VertexShaderInput
{
  float3 pos : POSITION;
  float3 color : COLOR0;
};

// The position is interpolated to the pixel value by the system. The per-vertex color data is also interpolated and passed through the pixel shader. 
struct PixelShaderInput
{
  float4 pos : SV_POSITION;
  float3 color : COLOR0;
};

Этот код определяет пару простых буферов констант

Ниже приведен пример семантики, используемой для определения значения, возвращаемого шейдером фрагментов:

// A pass-through for the (interpolated) color data.
float4 main(PixelShaderInput input) : SV_TARGET
{
  return float4(input.color,1.0f);
}

В этом случае SV_TARGET — это расположение целевого объекта отрисовки, в которое записывается цвет пикселя (определенный как вектор с четырьмя значениями с плавающей запятой) после завершения выполнения шейдера.

Дополнительные сведения об использовании семантики с Direct3D см . в разделе семантики HLSL.