我观察到一些奇怪的行为。我有一个32位无符号整数数组。我用一个整数来编码4个值,每个值的大小都是一个字节。然后我想将这样的缓冲区传递给顶点着色器
layout (location = 0) in uvec4 coords;
为了实现这一点,我使用VkVertexInputAttributeDescription
并将format
设置为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));
}
我以相反的顺序得到字节。向量类型是否使用不同的端序?
问题不在于Vulkan,而在于您的代码对正在发生的事情的解释。发送和接收。
回想一下,端序是关于一个字节在一个多字节值中的逻辑位置和一个字节在一个多字节值中的相对地址之间的(潜在的)差异。在小端序中,如果将一个四字节的值写入内存,第一个字节将是该值的最低有效字节。
Endianness既适用于读也适用于写,但是当将作为多字节值读写时,仅适用于。你的PackedUVec4
是不是一个多字节值;它是一个结构体,包含具有特定布局的字节。因此,如果您写入PackedUVec4
的x
组件,则您正在写入该结构的第一个字节,无论 CPU的端序如何。
当您告诉Vulkan将此数据读取为单个4字节值(VK_FORMAT_R32_UINT
)时,它会根据CPU的端位数来定义。但是你的代码没有生成与你的CPU的端序一致的数据;它是根据PackedUVec4
的布局生成的。所以内存中的第一个字节是x
。如果GPU读取这4个字节作为一个小的尾端4字节值,那么第一个字节将映射到4字节值的最低有效字节。
但是手动解码数据的代码正在解码错误的。它期望最低有效字节为w
。
如果你想让你的代码是端独立的,那么你需要GPU读取数据作为4个单独的字节,在内存中存储的顺序。这就是VK_FORMAT_R8G8B8A8_UINT
所代表的。如果你想让GPU在单个32位整数中读取它作为基于端序的顺序,那么它需要被CPU以方式写入。