如何创建一个紧密打包的无符号字节统一缓冲区?
Posted
技术标签:
【中文标题】如何创建一个紧密打包的无符号字节统一缓冲区?【英文标题】:How can I create a tightly packed uniform buffer of unsigned bytes? 【发布时间】:2020-02-29 20:49:10 【问题描述】:基本上是标题。这是一个包含数百万个数字的数组,所以我想尽量减少它在显卡上占用的空间。不幸的是,std140 布局中的数组具有 16 字节的基本对齐方式,而 GLSL 没有内置的 unsigned char
类型,所以我不确定如何有效地做到这一点。
【问题讨论】:
这个问题仍然缺乏细节,例如数据的大小、访问模式等。GPU 确实通过纹理和图像对象原生支持 8 位整数类型。除此之外,您可以通过uint
s 的数组将这些东西打包成一个线性SSBO。
通常,数组对齐指定数组中的第一个元素将在 16 字节边界上,而不是每个元素都将从 16 字节边界开始。
@jwdonahue:不在具有sdt140
布局的OpenGL 中。但是更高版本支持具有std430
布局的SSBO,这点不同。
你能把每个整数打包四个字节,然后在你的着色器中解码每个字节吗?整数的对齐方式为 4,因此应该正确打包。
@wcochran 不,每个数组元素的对齐方式是 std140
布局中 16 个字节的倍数,无论确切类型如何
【参考方案1】:
GLSL 没有与字节等效的类型。但是由于它的所有类型都由特定数量的字节组成,因此您可以从更大的类型中提取所需的字节。如uint
,要求大小为32位。
当然,字节序将是一个问题。声明 GPU 的字节序与为其提供数据的 CPU 的字节序相匹配。但是,当您从特定的 uint
获取字节时,您必须考虑到这一点。
当然,std140
布局不会让您创建一个紧密排列的 uint
数组。所以不要;创建一个紧密排列的 uvec4
数组。那是 4 个整数。
所以要从这样的 UBO 中获取特定的无符号字节,您必须这样做:
layout(binding = #, std140) uniform BlockName
uvec4 byte_array[NUM_BYTES / 16]; //NUM_BYTES must be a multiple of 16.
;
uint get_byte(uint byte_ix)
uint byte_in_uint = byte_ix % 4;
uint uint_in_vec = (byte_ix / 4) % 4;
uint vec_ix = byte_ix / 16;
uint bytes = byte_array[vec_ix][uint_in_vec];
return (bytes >> ((4 - byte_in_uint) * 8)) && 0xFF; //Little-endian. For Big-endian, remove the "4 -" part.
话虽这么说:
这是一个包含数百万个数字的数组
嗯,大多数卡片不允许您通过一个统一的块访问数百万个内容。统一块大小的限制仅保证至少为 16KB,大小通常在 64KB 左右。几乎没有“数百万”的东西。缓冲区对象本身可以保存您可以让系统分配的任何内容,但任何特定的glBindBufferRange(GL_UNIFORM_BUFFER, ...)
调用都必须限制为统一块大小。
如果您需要单个着色器来潜在地访问更多数据,那么您将不得不使用 SSBO 或缓冲区纹理。
【讨论】:
以上是关于如何创建一个紧密打包的无符号字节统一缓冲区?的主要内容,如果未能解决你的问题,请参考以下文章