вторник, 27 апреля 2010 г.

OIT and GI using DX11 linked lists

На developer.amd.com выложены слайды с GDC 2010, их можно найти на странице GPU Technical Publications. Одна из презентаций посвящена реализации OIT (думается, в Mecha Demo) от Nick Thibieroz и Holger Grün. Краткое описание алгоритма OIT можно прочитать в блоге Вольфганга Енджела - Order-Independent Transparency II. Кроме того, доступна русскоязычная статья на uraldev-е от Евгения Коростелева: Порядко-независимая прозрачность на GPU с использованием динамических списков.

Ранее я уже пробовал разобраться в шейдерах Mecha. Для этого пришлось написать hook-DLL для перехвата вызовов D3DCompileShader(). К сожалению, все шейдеры в демо зашиты в binary blob-ы, и всё, что можно сделать - это получить дизассемблированный код. Разобраться быстро в нём оказалось непросто, т. к. код по работе с OIT был густо перемешан с кодом расчёта освещения, сортировки и т. д. Тогда я отставил эту трудоёмкую задачу, и вот теперь стали доступны детали реализации.

OIT от AMD не использует prefix scan для расчёта смещений для записи фрагментов, как это описано в патенте Microsoft. Вместо этого используется R/W structured буфер, в элементах которого хранятся атрибуты фрагмента (цвет, глубина), и индекс предыдущего (следующего, как посмотреть) фрагмента в списке (если на пиксель экрана накладываются два и более фрагментов). Индекс указывает на элемент в structured buffer. Таким образом, полупрозрачные фрагменты организуются в памяти GPU в linked lists.

Преимущество этого метода в том, что запись в structured буфер всегда происходит последовательно, даже если фрагменты в буфер кадра приходят хаотически. В противовес этому, подход, применённый в DirectX SDK (и у меня), приводит к весьма хаотичному заполнению A-буфера. Для примера, стартовые позиции двух fragment bins для двух соседних пикселей уже различны. Добавьте к этому, что растеризатор выплёвывает фрагменты не линейно, а квадами 2х2, и получается безрадостная картина неупорядоченной записи в UAV (нужно отметить, что по моим тестам, при увеличении разрешения основной bottleneck заключался именно в заполении A-буфера, за ним следовала сортировка, и только потом - относительно дешёвый prefix scan). Поэтому на практике метод AMD на шаге аккумуляции фрагментов должен работать быстрее. Правда, в дополнение также используется т. н. Start Offset Buffer, но его элементы, в которые просходит запись, находятся в тех же позициях, что и фрагменты в буфере кадра.

На этапе сортировки фрагментов происходит traversal по этим linked lists, данные из различных участков памяти собираются в массив и сортируются. Теоретически такой traversal мог бы быть медленнее, чем линейная выборка fragment bins из A-буфера, но здесь мы можем просто читать из UAV, присоединив его как shader resource view. Т. к. random access текстур в GPU хорошо оптимизирован, этот шаг, вероятно, выполняется с хорошей скоростью.

P.S. Жаль только, что не могу реализовать алгоритм - Direct3D 11 железа больше нет под рукой :(
P.P.S. Хотя можно попробовать хотя бы с софтверной эмуляцией :)

2 комментария:

  1. у mecha все данные заархивированны (zip), HLSL-шейдера в этом же архиве (на вскидку не помню, но вроде .pak) - любой архиватор открывает. Модельку доставал оттуда же, а ее дескрипшн через PerfStudio.

    > запись в structured буфер всегда происходит последовательно
    откуда информация? Да, и по тестам RWTexture работает быстрее RWSB.

    у OIT на 64 слоя самая тяжелая стадия - сборка списка и сортировка, ближайшее время попробую ускорить
    а вообще алгоритм в филрейт упирается

    меня вот удивило, что счетчик у RWSB оч быстрый - не встречал информации почему?

    Интересно как оно все живет на Fermi. В презентации пишут, что мол там лучше Append-буфер использовать. Найти бы кого-нибудь для теста.

    ОтветитьУдалить
  2. >откуда информация? Да, и по тестам RWTexture работает быстрее RWSB.
    Потому что индексация основана на RWSB hidden counter. Это видно и из слайдов.

    >у OIT на 64 слоя самая тяжелая стадия - сборка >списка и сортировка, ближайшее время попробую >ускорить а вообще алгоритм в филрейт упирается
    Филлрейт - понятие растяжимое. Во что именно?
    Для облегчения сортировки думаю лучше всего маскировать стенселем участки экрана с разным overdraw и запускать сортируюший шейдер с разными глубинами сортировки + earlydepthstencil для реджектинга. Должно быть лучше чем юниформная сортировка для 64 элементов.

    >меня вот удивило, что счетчик у RWSB оч быстрый - не встречал информации почему?
    Потому что захардкоден в силиконе :)

    ОтветитьУдалить