uint64_t类型数组的UBO填充

时间:2018-08-19 12:46:12

标签: opengl glsl

我有以下情况。 UBO结构在一个数组中包含4个uint64_t。

  struct MaterialData{
     uint64_t  comps[4];
  };
  layout (std140, binding = 0) uniform MaterialBlock {
      MaterialData data[50];
  }material;

问题是,只有索引= 0才能给我正确的数据。但是,如果我更改为uint64_t的GLSL内置类型矢量,则一切正常:

  struct MaterialData{
     u64vec4  textures;
  };

它肯定与std140的填充规则有关。这就是OpenGL 4.5 specs所说的:

  

如果成员是标量或向量的数组,则基本比对   和数组步幅设置为匹配单个数组的基本对齐方式   元素,根据规则(1),(2)和(3),并四舍五入到   vec4的基本比对。数组的末尾可能有填充;的   数组后成员的基本偏移量四舍五入为   基本比对的下一个倍数。

所以我从这部分理解

  

基本对齐方式和数组步幅设置为与基本匹配   单个数组元素的对齐方式

每个数组的成员对齐方式是成员的大小,为8个字节。尽管这还不是很清楚。实际上它是行不通的。我可以与u64vec4融洽相处,但我想知道如何填充uint64_t数组?

2 个答案:

答案 0 :(得分:4)

您错过了关键短语:

  

并四舍五入到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数组。

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

答案 1 :(得分:2)

您已经在引用GL规范的相关部分,在这里我只是强调一下:

  

如果成员是标量或向量的数组,则根据规则(1),(2)将基本对齐方式和数组跨度设置为与单个数组元素的基本对齐方式匹配以及(3),并四舍五入到vec4的基本对齐方式

std140中,数组步长总是 16字节的倍数。 (这是与以后的std430的主要区别,SSBO允许这样做)。因此,如果您确实想要uint64_t[4]类型,则需要在每个元素上额外填充8个字节,从而浪费50%的存储空间。

我确实看到了两种选择:

  1. 只需使用u64vec4就可以了。由于甚至在GLSL中也为向量定义了[]运算符,因此与uint64_t[4]并没有太大区别。您只会得到其他繁琐的运算符。
  2. 由于您似乎仍在使用现代GL,因此请切换到std430布局的SSBO。