GLSL 结构数组 - 内存分配/对齐

Posted

技术标签:

【中文标题】GLSL 结构数组 - 内存分配/对齐【英文标题】:GLSL Struct Array - Memory Allocation / Alignment 【发布时间】:2021-12-29 16:17:57 【问题描述】:

我有一个带有结构数组的基本 GLSL 片段着色器。我希望能够根据运行我的程序的机器来确定数组的大小。

#version 410
#define MAX_DATA_SIZE %1

//32B (x8 FLOATS)
struct Data

    uint uintValue;//4B: 0
    float floatValue;//4B: 4
    sampler2D sampler;//16B: 5-8
;

uniform Data dataArray[MAX_DATA_SIZE];

想法是:

读取 GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 的值 将该值除以我的结构体大小(即 8),以获得数组的最大大小 在 QT 中将着色器作为 QString 读取,并将 %1 替换为计算出的最大大小

我的 NVIDIA GPU 运行正常。

问题出在我的英特尔集成 GPU 上。当我根据我的英特尔集成 GPU 告诉我的内容更新数组大小时(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 返回 4096/8 = 512),应用程序崩溃,似乎没有内存来分配给数组。

由于某种原因,实际的最大数组大小似乎是 32,而我的英特尔 GPU 对我撒谎。我在这里有什么遗漏或做错了吗?

我知道 UBO 会是更好的选择,但我正在处理不久前编写的代码,并且转换它需要时间。因此,我正在寻找您所说的“HOT FIX”。

【问题讨论】:

"我的结构的大小是 8" 这不是组件计数的工作方式。根据标准和 ARB_bindless_texture,您的结构的组件数为 4。 【参考方案1】:

除非您使用的是无绑定纹理,否则采样器类型不计入组件限制。因此,就 GLSL 本身而言,您的结构占用 2 个组件(每个标量仅计为一个)。

相反,采样器计入着色器阶段可以使用的纹理图像单元数量的限制。在许多(最近的)英特尔硬件上,片段阶段是 32。因此您的数组不能大于 32。

您的 NVIDIA 实现可能默默地对待这些采样器,就好像您在使用 ARB/NV_bindless_texture 一样。在这种情况下,每个采样器占用两个组件,因为它们被视为 64 位整数。所以你的结构会占用 4 个组件。

【讨论】:

这是有道理的。不过,我对组件数量感到有些困惑。这是我目前的逻辑:在计算组件时,您将计数四舍五入为 4 的倍数(vec4)。因此,如果没有采样器,计数将为 2 向上舍入为 4,而使用采样器仍为 4。还是仅用于计算填充? @rtavakko:“这是我目前的逻辑:在计算组件时,你会将计数四舍五入到 4 的倍数(vec4)。”你为什么要这样做?它在哪里说这种四舍五入发生了?默认块制服不像 UBO 中的制服那样工作。 如果我理解正确的话,这就是“不,这就是使用 std140 布局为 UBO 所做的事情”。感谢您对问题的回答。

以上是关于GLSL 结构数组 - 内存分配/对齐的主要内容,如果未能解决你的问题,请参考以下文章

分配初始化的、对齐的内存

什么是对齐内存分配?

malloc分配内存进行对齐的操作

自定义堆栈分配器中的 C++ 内存对齐

c++类型内存分配规则

c++类型内存分配规则