首页 > 解决方案 > uint64_t 类型数组的 UBO 填充

问题描述

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

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

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

  struct MaterialData{
     u64vec4  textures;
  };

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

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

所以我从这部分理解

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

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

标签: openglglsl

解决方案


你错过了关键短语:

并四舍五入到 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];
};

当然,这是非常浪费的。处理此问题的更好方法是使用 s 数组u64vec2

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


推荐阅读