Стадия сбора исходных данных в Direct3D10 и Direct3D11 - SIISII/DirectX GitHub Wiki
Стадия сбора исходных данных (input-assembler stage, IA) всегда является первой стадией графического конвейера. Она выполняет следующие функции:
- считывает из входных буферов заданную программистом информацию о вершинах и формирует из этих вершин примитивы;
- добавляет к считанной информации так называемые сгенерированные системой значения (system-genetated values) — идентификаторы примитивов, экземпляров и вершин;
- передаёт подготовленные данные на обработку вершинному шейдеру.
Чтобы подготовить стадию сбора исходных данных к работе, необходимо привязать к ней объект формата входных данных и буферы (вершинные и индексный), а также определить тип графических примитивов, описываемых этими буферами.
Входные буферы
Исходная информация содержится в вершинном и индексном буферах. Эти буферы, как и любые другие, являются ресурсами, создаваемыми с помощью метода ID3D10Device::CreateBuffer или ID3D11Device::CreateBuffer.
Вершинный буфер (vertex buffer) содержит всю информацию о вершинах, из которых образуются примитивы, подлежащие рендерингу. Конкретный набор содержащихся в нём данных и взаимное расположение полей задаются объектом формата входных данных (см. ниже).
Индексный буфер (index buffer) задаёт порядок выборки вершин из вершинного буфера, что, в свою очередь, определяет, из каких именно вершин формируются примитивы. Если индексный буфер не используется, вершины выбираются в порядке их следования в вершинном буфере.
Вершинных буферов может быть несколько, при этом каждый из них задаёт часть информации для одного и того же набора вершин. Индексный буфер может быть только один. Кроме того, возможно использование графического конвейера без входных буферов вообще.
Возможна работа и без входных буферов. В этом случае на вход вершинного шейдера будут поступать только значения, сгенерированные системой (в первую очередь ими будут номера вершин; зная номер обрабатываемой вершины, вершинный шейдер может сам сформировать её координаты и вернуть их в качестве результата своей работы).
Входные слоты
Данные поступают в графический конвейер через так называемые входные слоты. Технически каждый вершинный буфер привязывается к своему слоту; последний отвечает за выборку информации именно из этого буфера. После выборки информации из всех буферов она объединяется в набор параметров, описывающих одну вершину, и передаётся на вход вершинного шейдера.
Количество входных слотов зависит от уровня аппаратной поддержки: начиная с DirectX 10.1, можно использовать 32 слота с номерами от 0 до 31, с более ранней аппаратурой (от DirectX 9.1 до DirectX 10 включительно) — 16 слотов с номерами от 0 до 15. В то же время документация на все версии Direct3D утверждает, что у вершинного шейдера может быть не более 16 входных значений; возможно, дополнительные слоты могут использоваться только с буферами и текстурами, не обрабатываемыми стадией сбора исходных данных (например, с константными буферами).
Объект формата исходных данных
Объект формата исходных данных создаётся методом ID3D10Device::CreateInputLayout или ID3D11Device::CreateInputLayout. Оба этих метода имеют, по сути, идентичный набор параметров:
HRESULT CreateInputLayout(
const D3D11_INPUT_ELEMENT_DESC *pInputElementDescs,
UINT NumElements,
const void *pShaderBytecodeWithInputSignature,
SIZE_T BytecodeLength,
ID3D11InputLayout* *ppInputLayout);
-
pInputElementDescs
— массив структур типа D3D10_INPUT_ELEMENT_DESC или D3D11_INPUT_ELEMENT_DESC (см. ниже), описывающий входные данные. Каждый элемент массива соответствует одному элементу, находящемуся в том или ином вершинном буфере. -
NumElements
— количество элементов массива. -
pShaderBytecodeWithInputSignature
— указатель на скомпилированный шейдер, содержащий, помимо прочего, сигнатуру входных данных, которая сопоставляется с информацией из массива. После создания объекта формата исходных данных он может использоваться с любым вершинным шейдером, имеющим точно такую же сигнатуру.Если типы данных в объекте формата исходных данных не совпадают с таковыми в сигнатуре шейдера, выдаётся предупреждение. Оно может быть проигнорировано, если данные реинтерпретируются шейдером преднамеренно.
-
BytecodeLength
— размер скомпилированного шейдера. -
ppInputLayout
— адрес переменной, в которой будет сохранён указатель на интерфейс объекта формата исходных данных типа ID3D10InputLayout или ID3D11InputLayout. Эти интерфейсы унаследованы соответственно от интерфейса ID3D10DeviceChild или ID3D11DeviceChild и не имеют каких-либо дополнительных методов.
Как было сказано, формат исходных данных описывается массивом структур типа D3D10_INPUT_ELEMENT_DESC
или D3D11_INPUT_ELEMENT_DESC
. Эти структуры идентичны, различаясь лишь типом одного поля.
typedef struct D3D11_INPUT_ELEMENT_DESC
{
LPCSTR SemanticName;
UINT SemanticIndex;
DXGI_FORMAT Format;
UINT InputSlot;
UINT AlignedByteOffset;
D3D11_INPUT_CLASSIFICATION InputSlotClass;
UINT InstanceDataStepRate;
} D3D11_INPUT_ELEMENT_DESC;
-
SemanticName
— адрес строки, содержащей имя семантики HLSL в сигнатуре входных данных вершинного шейдера. Связь между информацией в буферах и параметрами шейдера устанавливается в процессе привязки ресурсов и шейдеров к конвейеру, используя имена семантик. -
SemanticIndex
— индекс семантики, используемый, если на вход подаётся несколько значений с одинаковым именем семантики. Если имя данной семантики является уникальным, индекс должен быть равен нулю. -
Format
— формат информации, соответствующей данному элементу описания. -
InputSlot
— номер входного слота, через который в конвейер поступает описываемая информация. -
AlignedByteOffset
— смещение в байтах от начала информации о вершине до данного элемента этой информации. КонстантаD3D10_APPEND_ALIGNED_ELEMENT
илиD3D11_APPEND_ALIGNED_ELEMENT
указывает, что данный элемент начинается сразу за предыдущим (с учётом возможного добавления байтов-заполнителей для обеспечения правильного выравнивания). -
InputSlotClass
— константа из перечисления D3D10_INPUT_CLASSIFICATION или D3D11_INPUT_CLASSIFICATION, определяющая класс исходных данных для одного входного слота. Возможные значения:-
D3D10_INPUT_PER_VERTEX_DATA
илиD3D11_INPUT_PER_VERTEX_DATA
— данный элемент описывает информацию, уникальную для каждой вершины. -
D3D10_INPUT_PER_INSTANCE_DATA
илиD3D11_INPUT_PER_INSTANCE_DATA
— данный элемент описывает информацию, уникальную для каждого экземпляра (см. описание идентификатора экземпляра).
-
-
InstanceDataStepRate
— количество экземпляров, которые должны быть отрисованы, прежде чем из данного буфера будут выбраны следующие данные. Это значение используется в том случае, если предыдущий параметр указывает, что данные соответствуют экземплярам, а не отдельным вершинам. Для повершинных данных он должен быть равен нулю.
Настройка стадии сбора исходных данных
Привязка вершинного буфера
Привязка вершинного буфера выполняется методом ID3D10Device::IASetVertexBuffers) или ID3D11DeviceContext::IASetVertexBuffers. Эти методы идентичны, за исключением типа интерфейса буфера:
void IASetVertexBuffers(
UINT StartSlot,
UINT NumBuffers,
ID3D11Buffer * const *ppVertexBuffers,
const UINT *pStrides,
const UINT *pOffsets);
-
StartSlot
— номер слота, через который будет осуществляться ввод данных из первого из буферов, привязываемых данным вызовом. Последующие буферы, привязываемые этим вызовом, соединяются со следующими слотами. -
NumBuffers
— количество привязываемых буферов. Это число не должно вызывать переполнение счётчика слотов, с которыми соединяются буферы. -
ppVertexBuffers
— адрес массива указателей на интерфейсы привязываемых буферов. -
pStrides
— адрес массива расстояний между элементами привязываемых буферов. Расстояние между элементами позволяет слоту переходить от одного элемента буфера к другому. Заметим, что это расстояние не обязательно равно размеру одного элемента (можно, например, использовать лишь чётные элементы буфера, и в таком случае расстояние между элементами будет равно удвоенному размеру элемента). -
pOffsets
— адрес массива смещений от начала каждого из буферов до первого элемента этого буфера, который будет использоваться.
Буфер, привязанный в данный момент для вывода информации из графического конвейера, не может быть привязан к стадии сбора исходных данных (буфер не может одновременно использоваться для ввода и вывода данных).
Привязка буфера в Direct3D10 не увеличивает счётчик ссылок на этот буфер, а в Direct3D11 — увеличивает.
Привязка объекта формата исходных данных
Объект формата исходных данных привязывается к стадии сбора исходных данных вызовом метода ID3D10Device::IASetInputLayout или ID3D11DeviceContext::IASetInputLayout. Эти методы идентичны, различаясь лишь типом интерфейса привязываемого объекта:
void IASetInputLayout(ID3D11InputLayout *pInputLayout);
Привязка объекта в Direct3D10 не увеличивает счётчик ссылок на этот объект, а в Direct3D11 — увеличивает.
Привязка индексного буфера
Привязка индексного буфера выполняется методом ID3D10Device::IASetIndexBuffer или ID3D11DeviceContext::IASetIndexBuffer. Эти методы идентичны, за исключением типа интерфейса буфера:
void IASetIndexBuffer(
ID3D11Buffer *pIndexBuffer,
DXGI_FORMAT Format,
UINT Offset);
-
pIndexBuffer
— указатель на интерфейс индексного буфера. -
Format
— формат данных в индексном буфере. Допустимы лишь два значения:DXGI_FORMAT_R16_UINT
иDXGI_FORMAT_R32_UINT
(16- и 32-разрядные целые числа без знака соответственно). -
Offset
— смещение в байтах от начала буфера до первого используемого значения.
Буфер, привязанный в данный момент для вывода информации из графического конвейера, не может быть привязан к стадии сбора исходных данных (буфер не может одновременно использоваться для ввода и вывода данных).
Привязка буфера в Direct3D10 не увеличивает счётчик ссылок на этот буфер, а в Direct3D11 — увеличивает.
Определение типа примитивов
Тип примитивов, описываемых входными буферами, задаётся вызовом метода ID3D10Device::IASetPrimitiveTopology или ID3D11DeviceContext::IASetPrimitiveTopology. Эти методы фактически идентичны, различаясь лишь формальным типом параметра-перечисления:
void IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY Topology);
Перечисление D3D11_PRIMITIVE_TOPOLOGY определяет большее число видов топологии, чем D3D10_PRIMITIVE_TOPOLOGY, поскольку в Direct3D11 поддерживается тесселяция, для которой новые виды топологии и предназначены. Новыми являются 32 значения от D3D11_PRIMITIVE_TOPOLOGY_1_CONTROL_POINT_PATCHLIST
до D3D11_PRIMITIVE_TOPOLOGY_32_CONTROL_POINT_PATCHLIST
, указывающие, что вершинный буфер должен рассматриваться как список патчей.
Определение текущих настроек стадии сбора исходных данных
Имеется возможность получить указатели на текущие привязанные буферы, узнать формат данных и определить тип установленной топологии. Эти операции выполняются с помощью следующих методов:
-
ID3D10Device::IAGetVertexBuffers и ID3D11DeviceContext::IAGetVertexBuffers;
-
ID3D10Device::IAGetIndexBuffer и ID3D11DeviceContext::IAGetIndexBuffer;
-
ID3D10Device::IAGetInputLayout и ID3D11DeviceContext::IAGetInputLayout;
-
ID3D10Device::IAGetPrimitiveTopology и ID3D11DeviceContext::IAGetPrimitiveTopology.