Opengl uint64_t类型数组的UBO填充

Opengl uint64_t类型数组的UBO填充,opengl,glsl,Opengl,Glsl,我有以下情况。在一个数组中保存4个uint64_t的UBO结构 struct MaterialData{ uint64_t comps[4]; }; layout (std140, binding = 0) uniform MaterialBlock { MaterialData data[50]; }material; 问题是,只有index=0提供了正确的数据。但是如果我更改为uint64\u t的GLSL内置类型vector,则一切正常: st

我有以下情况。在一个数组中保存4个uint64_t的UBO结构

  struct MaterialData{
     uint64_t  comps[4];
  };
  layout (std140, binding = 0) uniform MaterialBlock {
      MaterialData data[50];
  }material;
问题是,只有index=0提供了正确的数据。但是如果我更改为uint64\u t的GLSL内置类型vector,则一切正常:

  struct MaterialData{
     u64vec4  textures;
  };
这肯定与std140的填充规则有关。下面是说明:

如果成员是标量或向量数组,则基对齐 和阵列跨距设置为与单个阵列的基准对齐方式相匹配 元素,并四舍五入到 vec4的基础对齐。数组的末尾可能有填充;这个 数组后面的成员的基偏移向上舍入到 基础路线的下一个倍数

所以我从这一部分理解

基础对齐和阵列跨步设置为与基础匹配 单个阵列元素的对齐


每个数组的成员对齐是成员的大小,即8个字节。虽然这并不完全清楚。实际上它不起作用。我可以使用u64vec4,但我想知道如何填充uint64\t数组

您错过了关键短语:

并向上舍入到vec4的基准对齐

这意味着64位整数数组的步长与vec4:16的对齐方式相同。因此,数组中的64位整数包含8个字节的有用数据,后面是8个字节的填充,后面是下一个元素

<>所以在C++中,等效数组必须看起来像:

struct 64_bit_array_element
{
  std::uint64_t value;
  std::uint8_t padding[8];
};

struct UBO
{
  64_bit_array_element comps[4];
};
当然,这是极大的浪费。更好的处理方法是使用
u64vec2
s数组


或者您可以只使用SSBO和
std430
布局,规范中的违规行不适用于这些布局。

您已经引用了德国劳埃德船级社规范的相关部分,我只是在这里强调一下:

如果成员是标量或向量数组,则根据规则(1)、(2)和(3),将基本对齐方式和数组跨距设置为与单个数组元素的基本对齐方式相匹配,并向上取整为vec4的基本对齐方式

在std140中,数组步长始终是16字节的倍数。(顺便说一句,这是与SSBO允许的后期std430的一个主要区别)。因此,如果您真的需要
uint64\u t[4]
类型,则需要在每个元素中添加8个字节,从而浪费50%的存储空间

我确实看到了两种选择:

  • 只需使用
    u64vec4
    ,就可以了。由于GLSL中甚至为向量定义了
    []
    运算符,因此与
    uint64\u t[4]
    之间没有显著差异。你只需要额外的swizzling操作符
  • 由于您似乎仍然使用现代GL,请切换到具有
    std430
    布局的SSBO

  • 是的,事实上,使用阵列浪费空间。。。“在所有条件相同的情况下,SSBO访问速度可能会比UBO访问速度慢”,这让我觉得UBO在性能方面更为理想benchmarked@MichaelIV:存在诸如内存/性能权衡之类的问题。此外,如果阵列的大小很小,那么由于缓存,访问它的成本将很快被消除。最后,注意“一切平等”等词语;我写这些字不是因为我喜欢罗嗦。