Какое использование имеет скалярный спецификатор макета в EXT_scalar_block_layout? - PullRequest
2 голосов
/ 05 марта 2020

Вопрос

Какое использование имеет спецификатор макета scalar при доступе к буферу хранения в GL_EXT_scalar_block_layout? (см. ниже, например)

Какой будет вариант использования для scalar?

Фон

Я недавно запрограммировал простой Raytracer, используя расширение Vulkan и NVidias VkRayTracing и следил за этот урок . В разделе о ближайшем хит-шейдере требуется доступ к некоторым данным, которые хранятся в буферах хранения (с флагами использования vk::BufferUsageFlagBits::eStorageBuffer).

В шейдере используется расширение GL_EXT_scalar_block_layout и эти буферы Доступ к ним осуществляется следующим образом:

layout(binding = 4, set = 1, scalar) buffer Vertices { Vertex v[]; } vertices[];

Когда я впервые использовал этот код, слои проверки сказали мне, что структуры, подобные Vertex, имели недопустимую разметку, поэтому я изменил их, чтобы выровнять каждый элемент по 16-байтовым блокам:

struct Vertex {
    vec4 position;
    vec4 normal;
    vec4 texCoord;
};

с соответствующей структурой в C ++:

#pragma pack(push, 1)
struct Vertex {
    glm::vec4 position_1unused;
    glm::vec4 normal_1unused;
    glm::vec4 texCoord_2unused;
};
#pragma pack(pop)

Ошибки исчезли, и я получил работающий Raytracer. Но я до сих пор не понимаю, почему здесь используется ключевое слово scalar. Я нашел этот документ , говорящий о GL_EXT_scalar_block_layout-extension, но я действительно не понимаю этого. Возможно я просто не привык к терминологии glsl? Я не вижу причин, по которым мне пришлось бы использовать это.

Также я просто попытался удалить scalar, и он все еще работал без каких-либо различий, предупреждений или ошибок вообще. Был бы признателен за любые разъяснения или дополнительные ресурсы по этой теме c.

1 Ответ

5 голосов
/ 05 марта 2020

Макеты std140 и std430 выполняют небольшое округление размеров объектов смещения / выравнивания. std140 в основном делает любой нескалярный тип выровненным по тому же выравниванию, что и vec4. std430 это несколько ослабляет, но все же делает много округлений до выравнивания vec4.

scalar расположение означает в основном расположение объектов в соответствии с их скалярами компонентов. Все, что объединяет компоненты (векторы, матрицы, массивы и struct s), не влияет на макет. В частности:

  1. Все типы имеют размер / выравнивание только по максимальному выравниванию скалярных компонентов, которые они фактически используют. Таким образом, структура, содержащая один uint, имеет такой же размер / выравнивание, что и uint: 4 байта. По правилам std140 он будет иметь 16-байтовый размер и выравнивание.

    Обратите внимание, что этот макет делает vec3 и подобные типы действительно жизнеспособными , потому что тогда C и C ++ будут способны создавать правила выравнивания, которые соответствуют правилам GLSL.

  2. Шаг массива элементов в массиве основан исключительно на размере / выравнивании типа элемента, рекурсивно. Таким образом, массив uint имеет шаг массива 4 байта; согласно правилам std140, будет иметь 16-байтовый шаг .

  3. Выравнивание и заполнение имеют значение только для скаляров. Если у вас есть структура, содержащая uint, за которой следует uvec2, в std140/430, это потребует 16 байтов, с 4 байтами заполнения после первого uint. При компоновке scalar такая структура занимает всего 12 байтов (и выровнена по 4 байта), при этом uvec2 концептуально не выровнен. Поэтому заполнение существует только в том случае, если у вас есть меньшие скаляры, такие как uint16, за которым следует uint.

В указанном вами случае c макет scalar не требовался поскольку все используемые вами типы vec4 s.

...