Безопасно ли использовать блочный индекс в качестве точки привязки для UniformBufferObject, ShaderStorageBufferObjects и т. Д.?
Мне любопытно *BlockBinding
аргумент, используемый в нескольких функциях объекта буфера OpenGL.
Например, uniformBlockBinding
параметр в glUniformBlockBinding
, storageBlockBinding
в glShaderStorageBlockBinding
и соответствующий index
параметр в glBindBufferRange
а также glBindBufferBase
,
Я знаю, что звонки glUniformBlockBinding
а также glShaderStorageBlockBinding
не нужны, если точки привязки установлены в шейдерах с использованием таких квалификаторов макета, как:
layout (binding = 0) blockName {...}
и после тестирования на моей машине я заметил три вещи:
1) установка точек привязки с glUniformBlockBinding
а также glShaderStorageBlockBinding
переопределить точки привязки, установленные в шейдере, с помощью квалификаторов макета.
2) блочные индексы, возвращенные из glGetUniformBlockIndex
а также glGetProgramResourceIndex
упорядочены от 0 до n для каждого блока одного типа. Например, если шейдер содержит 3 однородных блока и 2 буферных блока, возвращаемые индексы будут равны [0,1,2] и [0,1] соответственно.
3) точки привязки, установленные в любом случае, не конфликтуют между типами. Например, установка одинакового блока для binding = 0 и буферного блока для binding = 0 полностью безопасна.
Имея в виду эти предположения (пожалуйста, исправьте меня, если они не обязательно верны и являются просто совпадением), есть ли причины, по которым мне не следует просто автоматически устанавливать код *BlockBinding
аргумент соответствующего индекса блока и избавить себя от необходимости задавать их вручную через gl*BlockBinding
или с классификаторами макета.
2 ответа
Имея в виду эти предположения (пожалуйста, исправьте меня, если они не обязательно верны и являются просто совпадением), есть ли причины, по которым мне не следует просто автоматически устанавливать код
*BlockBinding
аргумент соответствующего индекса блока и избавить себя от необходимости задавать их вручную черезgl*BlockBinding
или с классификаторами макета.
Потому что это было бы совершенно бесполезно.
Индекс блока произвольно назначается конкретному блоку. Одна платформа, индекс конкретного блока может быть 0, а другая сортирует имена так, что это индекс 2. Таким образом, ваш код должен будет запрашивать индексы блоков для каждого блока, который вы планируете использовать.
Принимая во внимание, что если вы указываете, какие индексы привязки использовать для определенного блока, вам не нужно ничего запрашивать. Ваш код знает, что индекс привязки 0 - это то место, куда идут ваши матрицы, индекс привязки 1 - то, куда идут ваши данные освещения и т. Д.
Что еще хуже, у вас может быть несколько шейдеров, которые используют один и тот же блок. Но вряд ли у них одинаковый блочный индекс. Принимая во внимание, что если вы назначаете им индекс привязки, вы можете присвоить им тот же индекс привязки. И поэтому вам не нужно повторно связывать буферы между изменениями в таких программах.
У меня когда-то был тот же вопрос. После некоторого изучения и особенно чтения авторитетного источника информации о GL: https://www.khronos.org/opengl/wiki/Uniform_Buffer_Object] Я почти уверен, что именно поэтому существует разделение между индексом блока и точкой привязки.
Представьте себе, что контекст рендеринга GL является портом, а программный объект glsl - кораблем. Точки привязки - это порты порта, а индексы блоков - двери в отсеки для хранения судна. Корабль должен состыковаться в порту, одна из его дверей должна быть выровнена с определенной гаванью, чтобы погрузить груз на судно (или наоборот). Аналогично, индекс блока должен быть связан с точкой привязки для данных, которые должны быть переданы между блоками шейдера и буферами контекста.
Благодаря такой конструкции индексы блоков и точки привязки являются независимыми объектами. Поэтому небезопасно просто приравнивать точку привязки к индексу блока, так как это может непреднамеренно переопределить точки привязки (которые могли быть пристыкованы другими кораблями).
Ваши наблюдения также могут быть объяснены:
- Индексы блоков и точки привязки начинают отсчитываться от 0 непрерывно (как вы видели в (2)).
- Каждый тип буферов (поскольку они находятся в контексте) имеют набор точек привязки, которые отделены от других типов (отсюда ваше наблюдение 3).
- Что касается вашего наблюдения 1, то да, установка ассоциации на стороне приложения вытесняет жестко закодированное связывание в шейдере.