Как реализовать / использовать атомный счетчик в шейдерном фрагменте Metal?
Я хочу реализовать алгоритм A-Buffer для прозрачности, независимой от порядка, в моем приложении Metal. В описании техники упоминается использование атомного счетчика. Я никогда не использовал ни одного из них или даже слышал о них. Я только что прочитал об атомарных переменных в спецификации языка металлического шейдинга, но не могу понять, как их реализовать или использовать.
У кого-нибудь есть опыт работы с этим в металле? Можете ли вы указать мне пример того, как установить и использовать простой целочисленный счетчик? По сути, при каждом проходе рендеринга мне нужно иметь возможность увеличивать целое число из фрагмента шейдера, начиная с нуля. Это используется для индексации в A-Buffer.
Спасибо!
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
,