Philip Taylor "Programmable Shaders for Direct 8.0" Опубликовано 15 января 2001

Программные шейдеры Direct3D, Часть 1

Добро пожаловать в DirectX. В прошлом месяце я представил вам обзор DirectX Graphics 8.0. Сейчас я хочу показать вам новые возможности программируемого конвейера. Появление программируемого конвейера является основным нововведением DirectX Graphics 8.0.

Программируемость

Имеются всего две программируемые секции в архитектуре Direct3D: вершинные шейдеры и пиксельные шейдеры. Вершинные шейдеры применяются до сборки вершин (vertex assembly) и операциями над ними. Пиксельные же шейдеры применяются после вызова функций DrawPrimitive или DrawIndexedPrimitive и генерируют пиксели, которые выводятся на экран. Программные шейдеры для операций над вершинами и пикселями позволяют достичь качества кино-эффектов в масштабе реального времени. Программируемость конвейера по-настоящему дает разработчику полную свободу в выборе способа реализации своих замыслов. Например, с помощью шейдеров могут быть реализованы следующие возможности:

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

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

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

Рисунок 1. Архитектура программируемого конвейера Direct3D

Вершинные шейдеры

Вершинные шейдеры заменили в старом фиксированном конвейере Direct3D функции модуля трансформации и освещения (T&L modul). Теперь обработка вершин выполняется вершинными шейдерами, которые обрабатывают одну вершину одновременно. Последовательность операций над вершинами в конвейере такова:

  1. Вершинная сборка (преобразование формата)
  2. Тесселляция
  3. Вершинный шейдер ( заменяет T&L этап )
  4. Сборка примитивов
  5. Общее отсечение
  6. Отсечение не лицевых граней
  7. Перспективное деление
  8. Экранное преобразование

В конце этих операций получается индивидуальная, готовая к растеризации вершина, которая содержит преобразованную позицию (x, y, z, и w), цвет, текстурные координаты, интенсивность тумана и размер точки. Последующая обработка заключается в преобразовании позиции вершины на экран, сборке вершин в примитивы и отсечении полученных примитивов. Вершинный шейдер не выполняет эти операции. Каждый шейдер состоит из декларации, которая определяет интерфейс шейдера, и последовательности команд.

Раздел декларации определяет внешний интерфейс вершинного шейдера. Он связывает входные данные с его внутренними регистрами. Для этого в Direct3D появляется понятие потока. Поток - это унифицированный массив, каждый элемент в котором содержит информацию о вершине: позицию, цвет и т.д. Потоки позволяют графическим чипам параллельно использовать несколько буферов вершин. Следовательно:

Метод IDirect3DDevice8::SetStreamSource связывает буфер вершин с потоком, создавая ассоциацию между вершинными данными и одним из нескольких потоков, для последующей обработки примитивов. Ссылки на данные из потока не происходит до вызова функции рисования примитивов, как например IDirect3DDevice8::DrawPrimitive.

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

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

Тип ресурса
Макс. количество
   Входные регистры (Input registers)
16
   Константные регистры (Constant registers)
96
   Временные регистры (Temp registers)
12
   Адресный регистр (Address register)
1
   Выходные регистры (Output registers)
зависит от реализации
   Максимальное количество команд
128

Таблица 1. Ресурсы вершинного шейдера

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

op dest, src0,src1,src2, где

op - команда
dest - регистр, куда записываются результаты команды
scr[0,1,2] - входные регистры , количество которых зависит от конкретной команды

Команды вершинных шейдеров бывают двух типов: основные команды и макро-команды. Хочется отметить, что в шейдерах нет команд перехода и циклов. Каждая основная команда выполняется за один такт, а макро-команды, т.к. являются сокращением последовательности нескольких основных команд, выполняются за один такт и более.

Команда
Описание
Количество тактов
add
   сумма
1
dp3
   трех-компонентный dot-product
1
dp4
   четырех-компонентный dot-product
1
dst
   вектор расстояния
1
expp
   экспоненциал 10-битной точности
1
lit
   световой коэффициент
1
logp
   логарифм 10-битной точности
1
mad
   произведение и сложение
1
max
   максимум
1
min
   минимум
1
mov
   копирование
1
mul
   произведение
1
rcp
   обратная величина
>1
rsq
   обратный квадратный корень
>1
sge
   установить, если больше или равно
1
slt
   установить, если меньше
1
sub
   разность
1

Таблица 2. Основные команды вершинного шейдера

Команда
Описание
Количество тактов
exp
   экспоненциал двойной точности
12
frc
   доля
3
log
   логарифм двойной точности
12
m3x2
   3x2 произведение вектора и матрицы
2
m3x3
   3x3 произведение вектора и матрицы
3
m3x4
   3x4 произведение вектора и матрицы
4
m4x3
   4x3 произведение вектора и матрицы
3
m4x4
   4x4 произведение вектора и матрицы
4

Таблица 3. Макро-команды вершинного шейдера

Команда
Описание
Количество тактов
def
   определить константу
 
vs
   версия и тип шейдера
 

Таблица 4. Другие команды вершинного шейдера

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

Рисунок 2. Архитектура вершинного шейдера

Пример вершинного шейдера, выполняющего одно матричное преобразование с константным цветом:

vs.1.0
dp4 r0.x, v0, c[0] ; базовое преобразование
dp4 r0.y, v0, c[1]
dp4 r0.z, v0, c[2]
dp4 r0.w, v0, c[3]
mov oD0, c[4] ; заносим константный цвет в выходной регистр цвета
mov oPos, r0 ; заносим преобразованную позицию в выходной регистр позиции

Этот шейдер содержит шесть основных команд и выполняется за шесть тактов.

Hosted by uCoz