Стадия сбора исходных данных в Direct3D10 и Direct3D11 - SIISII/DirectX GitHub Wiki

Стадия сбора исходных данных (input-assembler stage, IA) всегда является первой стадией графического конвейера. Она выполняет следующие функции:

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

Входные буферы

Исходная информация содержится в вершинном и индексном буферах. Эти буферы, как и любые другие, являются ресурсами, создаваемыми с помощью метода 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, указывающие, что вершинный буфер должен рассматриваться как список патчей.

Определение текущих настроек стадии сбора исходных данных

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