glsl memoryBarrierShared полезность
Меня интересует полезность памяти BarrierShared.
Действительно, когда я смотрю документацию для барьерной функции: я читаю:
Для любого данного статического экземпляра барьера в вычислительном шейдере все вызовы в пределах одной рабочей группы должны войти в него, прежде чем любой из них сможет продолжить работу после него. Это гарантирует, что значения, записанные одним вызовом до данного статического экземпляра барьера, могут быть безопасно прочитаны другими вызовами после их обращения к тому же статическому экземпляру барьера. Поскольку вызовы могут выполняться в неопределенном порядке между этими вызовами барьера, значения выходной переменной для каждой вершины или для каждого патча или любой общей переменной будут неопределенными в ряде случаев.
Итак, если мы можем безопасно читать значения после использования барьера, почему мы видим в некотором коде
memoryBarrierShared();
barrier();
или что-то не так, как
barrier();
memoryBarrierShared();
Итак, мой вопрос: какова цель memoryBarrier{Shared,...}, если достаточно использовать барьер?
Для memoryBarrierBuffer/Image я могу понять, если мы используем несколько этапов, но для общего я понятия не имею...
1 ответ
Это на самом деле в споре в настоящее время.
GLSL 4.50 совершенно ясно показывает, что явные барьеры памяти не нужны. Тот barrier
в вычислительный шейдер входят все барьеры памяти.
Тем не менее, GLSL ES 3.20 в равной степени ясно показывает, что barrier
не включает в себя барьеры памяти любого вида:
Для вычислительных шейдеров барьер влияет только на поток управления и сам по себе не синхронизирует доступ к памяти. В частности, он не гарантирует, что значения, записанные одним вызовом до данного статического экземпляра
barrier()
могут быть безопасно прочитаны другими вызовами после их обращения к тому же статическому экземпляруbarrier()
, Для достижения этого требуется использование обоихbarrier()
и барьер памяти.
В частности, автономный компилятор glslang всегда будет использовать формулировку GLSL ES. Поэтому, если вы генерируете SPIR-V для подачи в Vulkan, вы должны следовать правилам ES здесь. Ну, пока они это не исправят, так или иначе.
Тем не менее, формулировка ES имеет гораздо больше смысла, так как полный барьер памяти для всего довольно дорого. Особенно, если вам нужно синхронизировать доступ к общим переменным.
Я бы предложил использовать барьер памяти вместе с barrier
вызов. Таким образом, ваш шейдер будет корректным, даже если он будет немного медленнее в некоторых реализациях. Однако, если вы собираетесь использовать барьеры памяти вместе с barrier
звонки, тогда барьер памяти должен стоять первым. Выполнение барьера памяти после синхронизации выполнения не является правильным.