Если «буфер» является «согласованным», есть ли разница между чтением поля и выполнением «atomicAdd(field, 0)»?

Это с семантикой Вулкана, если это имеет значение.

Предположим следующее:

layout(...) coherent buffer B
{
    uint field;
} b;

Скажем, поле модифицируется другими вызовами того же шейдера (или производного шейдера) через функции atomic*().

Если вызов шейдера хочет выполнить атомарное чтение из этого field (с той же семантикой, что и atomicCounter() в GLES, если бы вместо этого был atomic_uint), есть ли какая-либо разница между следующими двумя (кроме очевидного того, что один из них выполняет запись как и читать)?

uint read_value = b.field;
uint read_value2 = atomicAdd(b.field, 0);

Этот вопрос требует более подробной информации. Например, что означает «достаточно»? «Достаточно» для выполнения какой операции? coherent имеет значение относительно пары операций. С какой операцией вы хотите сделать атомарный доступ coherent? Какая связь между этими двумя операциями? И так далее. Вопрос, как указано, просто не содержит достаточной информации.

Nicol Bolas 19.07.2019 16:58

Он эмулирует атомарные счетчики, поэтому coherent с другими atomicAdd операциями над тем же uint (которые эмулируют atomicCounterIncrement и atomicCounterDecrement).

Shahbaz 19.07.2019 17:27

Другие atomicAdd операции куда? На той же стадии шейдера? На стадиях производных шейдеров? На этапах шейдера от последующих команд рендеринга? Утверждение, что вы «эмулируете атомарные счетчики», ничего не говорит о реальных операциях, которые вы выполняете.

Nicol Bolas 19.07.2019 17:31

Очевидно, что последующие команды рендеринга нуждаются в других барьерах. Я спрашивал о других вызовах того же шейдера (как указано в одном из вопросов). Я не думал о производных шейдерных стадиях, мне было бы любопытно узнать, имеет ли это значение (может быть, на мозаичном графическом процессоре?). --- Извините, я не был более конкретным, я предположил, что совершенно очевидно, как atomic_uint будет эмулироваться с помощью buffer AC { uint counters[]; } ac;

Shahbaz 19.07.2019 17:49

И я хочу сказать, что то, как вы это имитируете, зависит от вашего варианта использования. Здесь нет универсального решения.

Nicol Bolas 19.07.2019 17:53

Я чувствую, что мои детализированные вопросы на самом деле совершенно не зависят от имитации атомарных счетчиков. Например, я спрашиваю, если буфер coherent и вы читаете из него, а также atomic*() из него, может ли прочитанное значение кэшироваться более локально, чем результат атомарных операций. Ответ «да/нет» на этот (и на другой вопрос) даст мне достаточно информации, чтобы знать, что мне нужно знать для эмуляции.

Shahbaz 19.07.2019 18:09

Позвольте мне перефразировать вопрос, чтобы не упоминать атомные счетчики.

Shahbaz 19.07.2019 18:10

И что означает «кэшируется более локально» в отношении фактического поведения?

Nicol Bolas 19.07.2019 18:19

Скажем, если результат atomicAdd(field) (записанное значение) хранится в L2, а чтение field приводит к его кэшированию в L1 (что делает будущие модификации другими вызовами невидимыми), это будет более локальным (что, по-видимому, не является правильную терминологию).

Shahbaz 19.07.2019 18:21

Я хочу сказать, что это вопрос конкретной реализации, а не поведение. Значение coherent определяется с точки зрения поведения, отношения между чтением и записью из и в различные места. Реализации должны проработать детали кешей, чтобы реализовать эту реализацию. И эти детали будут специфичны для реализации, а не для чего-то полезного в целом.

Nicol Bolas 19.07.2019 18:23

Правильно, я хотел спросить о поведении coherent, но думал о том, как это реализовано. Итак, теперь вопрос понятен?

Shahbaz 19.07.2019 18:30
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
11
563
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Чтобы напрямую ответить на вопрос, эти две строки кода генерируют разные инструкции с разными характеристиками производительности и использованием аппаратного конвейера.

uint read_value = b.field;                 // generates a load instruction
uint read_value2 = atomicAdd(b.field, 0);  // generates an atomic instruction

В разделе 4.10 квалификаторов памяти GLSL-спецификация отмечается, что coherent касается только видимости операций чтения и записи между вызовами (потоками шейдера). Они также оставили комментарий о подразумеваемой производительности:

When accessing memory using variables not declared as coherent, the memory accessed by a shader may be cached by the implementation to service future accesses to the same address. Memory stores may be cached in such a way that the values written might not be visible to other shader invocations accessing the same memory. The implementation may cache the values fetched by memory reads and return the same values to any shader invocation accessing the same memory, even if the underlying memory has been modified since the first memory read. While variables not declared as coherent might not be useful for communicating between shader invocations, using non-coherent accesses may result in higher performance.

Точкой когерентности в системах памяти GPU обычно является кеш последнего уровня (кэш L2), что означает, что все когерентные обращения должны выполняться кешем L2. Это также означает, что когерентные буферы нельзя кэшировать в L1 или других кэшах, расположенных ближе к шейдерным процессорам. Современные графические процессоры также имеют выделенное атомарное оборудование в кэшах L2; обычная нагрузка не будет использовать их, но atomicAdd(..., 0) пройдет через них. Атомное оборудование обычно имеет меньшую пропускную способность, чем полный кэш L2.

Спасибо, что подтвердили мои подозрения. Я понимаю, что они генерируют разные сборки. Мой вопрос был действительно о том, могут ли они потенциально «вести себя» по-другому. Другими словами, гарантируется ли, что простое чтение переменной всегда возвращает то же значение, что и atomicAdd(var, 0)? Я все больше убеждаюсь, что это так.

Shahbaz 22.07.2019 21:22

Кстати, я очень хорошо знаком с GCN, и я могу сказать, что в этой архитектуре они будут эквивалентны (с некоторыми предположениями о драйверах). То, что я ищу, - это спецификация, гарантирующая, что так будет всегда. Я предполагаю, что ваша цитата косвенно говорит об этом: «При доступе к памяти с использованием переменных, не объявленных как когерентные, память, к которой обращается шейдер, может кэшироваться реализацией для обслуживания будущих обращений к тому же адресу». Итак, (!coherent => cached), хотя математически мы не можем вывести это (coherent => !cached), но я бы больше связал это с плохой формулировкой.

Shahbaz 22.07.2019 21:25
Ответ принят как подходящий

SPIR-V имеет инструкцию OpAtomicLoad. Предположительно, существует по крайней мере одно устройство, в котором неатомарная загрузка не может заменить атомарную загрузку, независимо от того, какой квалификатор имеет дескриптор буфера.

К сожалению, мне известно, что не существует конструкции Vulkan GLSL, которая может переводиться в OpAtomicLoad.

Другие вопросы по теме

Зачем очередям в семействе очередей в Vulkan приоритет, если мы не можем их различить?
Почему мне не нужны барьеры памяти, когда я начинаю рисовать на полученном образе цепи обмена?
Нужно ли добавлять включенные расширения отладки и уровни проверки на устройство при его создании, если они уже добавлены в экземпляр?
Может ли Vulkan/MoltenVK работать под armv7s?
Vulkan-hpp переинтерпретирует класс нестандартной компоновки в другой класс. Это законно?
Степень поддержки использования образов Vulkan Swapchain в качестве места назначения передачи
Vulkan, есть ли способ изменить смещение одного динамического юниформ-буфера, оставив остальные неизменными?
Опасность Vulkan WaW и барьер памяти
Исключение Windows в отношении amdvlk64.dll при попытке создать экземпляр vulkan
Передача права собственности на ресурсы Vulkan по сравнению с VK_SHARING_MODE_CONCURRENT и производительностью различных семейств очередей