0

我观察到一些奇怪的行为。我有一个无符号 32 位整数数组。我使用一个整数来编码 4 个值,每个值大小为 1 个字节。然后我想将这样的缓冲区传递给顶点着色器

layout (location = 0) in uvec4 coords;

为了实现这一点,我使用VkVertexInputAttributeDescriptionwith formatset to VK_FORMAT_R8G8B8A8_UINT。我已经定义了这样方便的结构

struct PackedUVec4{
   unsigned char x;
   unsigned char y;
   unsigned char z;
   unsigned char w;
};

然后我构建我的缓冲区,PackedUVec4[]然后将此类缓冲区发送到 GPU。但是,我观察到的是字节顺序被交换了。例如,如果我有

layout (location = 0) in uvec4 coords;
void main(){
   debugPrintfEXT("%v4d", coords);
}

它似乎打印了正确的输出。但是如果将格式更改为VK_FORMAT_R32_UINT并尝试运行

layout (location = 0) in uint coords;
void main(){
    uint w = coords & 255u;
    uint z = coords/256 & 255u;
    uint y = coords/(256*256) & 255u;
    uint x = coords/(256*256*256) & 255u;
    debugPrintfEXT("%v4d", uvec4(x,y,z,w));
}

我以相反的顺序得到字节。向量类型是否使用不同的字节序?

4

1 回答 1

2

问题不在于 Vulkan,而在于您的代码对正在发生的事情的解释。既发送又接收。

回想一下,字节顺序是关于多字节值中字节的逻辑位置与多字节值中字节的相对地址之间的(潜在)差异。在 little endian 中,如果您将一个四字节的值写入内存,则第一个字节将是该值的最低有效字节。

字节序适用于读取和写入,但仅在将多字节值作为多字节值读取/写入时。你PackedUVec4不是多字节值;它是一个包含具有特定布局的字节的结构。因此,如果您写入xa 的组件PackedUVec4,您将写入该结构的第一个字节,而不管您的 CPU 的字节序。

当您告诉 Vulkan 将此数据作为单个 4 字节值 ( VK_FORMAT_R32_UINT) 读取时,它会按照 CPU 的字节序定义。但是您的代码没有按照您的 CPU 的字节序生成该数据;它根据 a 的布局生成它PackedUVec4。所以内存中的第一个字节是x. 如果 GPU 将这 4 个字节作为 little endian 4 字节值读取,则第一个字节将映射到 4 字节值的最低有效字节。

但是您手动解码数据的代码解码错误。它期望最低有效字节为w.

如果您希望您的代码与字节序无关,那么您需要 GPU 按存储在内存中的顺序将数据读取为 4 个单独的字节。这就是所VK_FORMAT_R8G8B8A8_UINT代表的。如果您希望 GPU 将其作为单个 32 位整数内的基于字节序的顺序读取,则需要由 CPU 以这种方式写入。

于 2021-08-14T14:15:52.233 回答