EXT_scalar_block_layout 中的布局说明符标量有什么用?

What use has the layout specifier scalar in EXT_scalar_block_layout?

问题

访问 GL_EXT_scalar_block_layout 中的存储缓冲区时,scalar 布局说明符有什么用? (例如,见下文)

scalar 的用例是什么?

背景

我最近使用 Vulkan 和 NVidias VkRayTracing 扩展编写了一个简单的 Raytracer,并且正在关注 this tutorial。在关于最近命中着色器的部分中,需要访问存储在井存储缓冲区中的一些数据(带有使用标志 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关键字。我发现 this document 说的是 GL_EXT_scalar_block_layout-extension,但我真的不明白。可能我只是不习惯 glsl 术语?我看不出有任何理由必须使用它。

此外,我只是尝试删除 scalar,它仍然可以正常工作,没有任何区别、警告或错误。如有任何关于此主题的说明或更多资源,我们将不胜感激。

std140std430 布局对对象的 offsets/alignments 大小做了相当多的舍入。 std140 基本上使任何非标量类型对齐到与 vec4 相同的对齐方式。 std430 稍微放松了一点,但它仍然做了很多四舍五入到 vec4 的对齐。

scalar布局基本上是指根据对象的组件标量来布局对象。任何聚合组件(向量、矩阵、数组和 structs)的东西都不会影响布局。特别是:

  1. 所有类型 sized/aligned 仅与它们实际使用的标量组件的最高对齐。因此,包含单个 uint 的结构是 sized/aligned 到与 uint 相同的 size/alignment:4 个字节。在 std140 规则下,它将具有 16 字节大小和对齐方式。

    请注意此布局 ,因为 C 和 C++ 将能够创建映射到 GLSL 的对齐规则。

  2. 数组中元素的数组步幅完全基于元素类型的size/alignment,递归。所以 uint 的数组有一个 4 字节的数组步幅;根据 std140 规则,.

  3. 对齐和填充仅对标量有影响。如果您有一个包含 uint 后跟 uvec2 的结构,在 std140/430 中,这将需要 16 个字节,并在第一个 uint 之后填充 4 个字节。在 scalar 布局下,这样的结构仅占用 12 个字节(并对齐到 4 个字节),而 uvec2 在概念上未对齐。因此,仅当标量较小时才存在填充,例如 uint16 后跟 uint.

在您展示的特定情况下,scalar 布局是不必要的,因为您使用的所有类型都是 vec4s。