Как реализовать / использовать атомарный счетчик в шейдере фрагментов металла?

Я хочу реализовать алгоритм A-Buffer для прозрачности, не зависящей от порядка, в моем приложении Metal. В описании техники упоминается использование атомного счетчика. Я никогда не пользовался одним из них и даже не слышал о них. Я только что прочитал об атомарных переменных в спецификации языка Metal Shading, но не могу понять, как на самом деле их реализовать или использовать.

У кого-нибудь есть опыт работы с ними в Metal? Не могли бы вы указать мне на пример того, как настроить и использовать простой целочисленный счетчик? По сути, на каждом проходе рендеринга мне нужно иметь возможность увеличивать целое число внутри фрагментного шейдера, начиная с нуля. Это используется для индексации в A-буфере.

Спасибо!


person bsabiston    schedule 10.11.2017    source источник


Ответы (1)


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

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

fragment FragmentOut my_fragment_func(device atomic_uint &counter [[buffer(0)]], ...)
{
    ...
}

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

Чтобы атомарно увеличить атомарную переменную на 1 и получить предыдущее значение, вы можете сделать это:

    uint value = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);

Начальное значение атомарной переменной берется из содержимого буфера в точке перед выполнением команды рисования или отправки. Это не задокументировано как таковое в спецификации, но размер и битовая интерпретация атомарного типа, похоже, соответствуют соответствующему неатомарному типу. То есть вы должны записать uint (он же unsigned int или uint32_t) в буфер для инициализации atomic_uint.

person Ken Thomases    schedule 10.11.2017
comment
Спасибо, отличное объяснение! Общий обзор - это именно то, что мне нужно. Извините, я не предоставил более подробной информации - я еще не начал писать шейдер, я просто узнаю, достаточно ли я понимаю, чтобы продолжить его. - person bsabiston; 10.11.2017
comment
Я ДЕЙСТВИТЕЛЬНО интересуюсь ядрами / шейдерами для металлических вычислений, но я не знаю ни одного источника / книги / сайта, который объясняет оптимизацию / функции, подобные упомянутым выше. Я написал много шейдеров, но понятия не имею, что такое блоки изображения и вообще множество функций в Metal. Например. как, черт возьми, я могу реализовать собственный MPSGaussianBlur со случайным размером ядра на пиксель, который по производительности близок к реализации Apple? Я знаю, что это будет два прохода X, Y, но это первый шаг. Я чувствую, что в этих графических процессорах есть огромный потенциал, и мы лишь поверхностно его затрагиваем. - person Summon; 05.09.2019