Константы шейдера (HLSL)
В модели 4 шейдера константы шейдера хранятся в одном или нескольких буферных ресурсах в памяти. Они могут быть организованы в два типа буферов: буферы констант (cbuffers) и буферы текстур (tbuffers). Буферы констант оптимизированы для использования константных переменных, что характеризуется более низким уровнем задержки доступа и более частым обновлением из ЦП. По этой причине к этим ресурсам применяются дополнительные ограничения размера, макета и доступа. К буферам текстур обращаются такие как текстуры и лучше подходят для произвольных индексированных данных. Независимо от типа используемого ресурса нет ограничения на количество буферов констант или буферов текстур, которые может создать приложение.
Объявление буфера константы или буфера текстуры очень похоже на объявление структуры в C с добавлением ключевых слов register и packoffset для ручного назначения регистров или упаковки данных.
Имя bufferType [: register(b#)] { VariableDeclaration [: packoffset(c#.xyzw)]; ... };
Параметры
-
BufferType
-
[in] Тип буфера.
BufferType Description cbuffer буфер констант tbuffer Буфер текстуры -
Имя
-
[in] Строка ASCII, содержащая уникальное имя буфера.
-
register(b#)
-
[in] Необязательное ключевое слово, используемое для ручного упаковки константных данных. Константы можно упаковывать в регистр только в буфере констант, где начальный регистр присваивается номером регистра (#).
-
ПеременнаяDeclaration
-
[in] Объявление переменной, аналогично объявлению элемента структуры. Это может быть любой тип или объект эффекта HLSL (кроме текстуры или объекта sampler).
-
packoffset(c#.xyzw)
-
[in] Необязательное ключевое слово, используемое для ручного упаковки константных данных. Константы можно упаковывать в любой буфер констант, где номер регистра присваивается (#). Упаковка подкомпонентов (с использованием swizzling xyzw) доступна для констант, размер которых соответствует одному регистру (не пересекает границу регистра). Например, не удалось упаковать float4 в один регистр, начиная с компонента y, так как он не будет соответствовать регистру четырех компонентов.
Замечания
Буферы констант сокращают пропускную способность, необходимую для обновления констант шейдера, позволяя константы шейдера группироваться и фиксироваться одновременно, а не выполнять отдельные вызовы для фиксации каждой константы отдельно.
Буфер константы — это специализированный ресурс буфера, к которому осуществляется доступ, как к буферу. Каждый буфер констант может содержать до 4096 векторов; каждый вектор содержит до четырех 32-разрядных значений. Можно привязать до 14 буферов констант на каждом этапе конвейера (для внутреннего использования зарезервированы 2 дополнительных слотов).
Буфер текстуры — это специализированный ресурс буфера, доступ к которому осуществляется как текстура. Доступ к текстурам (по сравнению с доступом к буферу) может иметь более высокую производительность для произвольных индексированных данных. На каждом этапе конвейера можно привязать до 128 буферов текстур.
Ресурс буфера предназначен для минимизации затрат на настройку констант шейдера. Платформа эффектов (см. интерфейс ID3D10Effect) будет управлять обновлением буферов констант и текстур или использовать API Direct3D для обновления буферов (см. сведения о копировании и доступе к данным ресурсов (Direct3D 10). Приложение также может копировать данные из другого буфера (например, целевого объекта отрисовки или целевого объекта вывода потока) в буфер констант.
Дополнительные сведения об использовании буферов констант в приложении D3D10 см. в статьях "Типы ресурсов" (Direct3D 10) и создание буферных ресурсов (Direct3D 10).
Дополнительные сведения об использовании буферов констант в приложении D3D11 см. в разделе "Введение в буферы в Direct3D 11 " и "Практическое руководство. Создание буфера константы".
Буфер констант не требует привязки представления к конвейеру. Однако буфер текстуры требует представления и должен быть привязан к слоту текстуры (или должен быть привязан к SetTextureBuffer при использовании эффекта).
Существует два способа упаковки данных констант: использование регистра (DirectX HLSL) и ключевых слов packoffset (DirectX HLSL).
Различия между Direct3D 9 и Direct3D 10 и 11:
- В отличие от автоматического выделения констант в Direct3D 9, который не выполнял упаковку и вместо этого присваивал каждой переменной набору регистров float4, переменные константы HLSL следуют правилам упаковки в Direct3D 10 и 11.
Организация буферов констант
Буферы констант сокращают пропускную способность, необходимую для обновления констант шейдера, позволяя константы шейдера группироваться и фиксироваться одновременно, а не выполнять отдельные вызовы для фиксации каждой константы отдельно.
Лучший способ эффективного использования буферов констант — упорядочить переменные шейдера в буферы констант на основе их частоты обновления. Это позволяет приложению свести к минимуму пропускную способность, необходимую для обновления констант шейдера. Например, шейдер может объявлять два буфера констант и упорядочивать данные в каждом из них на основе их частоты обновления: данные, которые необходимо обновить на основе каждого объекта (например, матрица мира), группируются в буфер констант, который можно обновить для каждого объекта. Это отличается от данных, характеризующих сцену и поэтому, скорее всего, будет обновляться гораздо реже (когда сцена изменяется).
cbuffer myObject
{
float4x4 matWorld;
float3 vObjectPosition;
int arrayIndex;
}
cbuffer myScene
{
float3 vSunPosition;
float4x4 matView;
}
Буферы констант по умолчанию
Доступны два буфера констант по умолчанию, $Global и $Param. Переменные, помещенные в глобальную область, добавляются неявно в $Global cbuffer, используя тот же метод упаковки, который используется для cbuffers. Универсальные параметры в списке параметров функции отображаются в буфере констант $Param при компиляции шейдера за пределами платформы эффектов. При компиляции внутри платформы эффектов все униформы должны разрешаться переменным, определенным в глобальной области.
Примеры
Ниже приведен пример из примера Skinning10, который представляет собой буфер текстуры, состоящий из массива матриц.
tbuffer tbAnimMatrices
{
matrix g_mTexBoneWorld[MAX_BONE_MATRICES];
};
В этом примере объявление вручную назначает буфер констант для запуска с определенного регистра, а также упаковывает определенные элементы подкомпонентами.
cbuffer MyBuffer : register(b3)
{
float4 Element1 : packoffset(c0);
float1 Element2 : packoffset(c1);
float1 Element3 : packoffset(c1.y);
}