Glsl 在主机之间通信bvec2阵列->;着色器和/或着色器->;着色器

Glsl 在主机之间通信bvec2阵列->;着色器和/或着色器->;着色器,glsl,vulkan,compute-shader,Glsl,Vulkan,Compute Shader,我需要在计算着色器中为数组的每个条目传递两个布尔值。现在,我将从cpu获取这些值,但稍后我将希望从在该值之前运行的另一个计算着色器生成这些值。我的工作原理如下: 使用glm::bvec2我可以将布尔值相对打包到内存中(bvec每字节存储一个布尔值。可能会更好,但现在就可以了,我总是可以手动打包)。然后,我使用vkMapMemory将数据放入Vulkan缓冲区(然后将其复制到设备本地缓冲区,但这可能与此无关) 不幸的是,GLSL的bvec2并不等同于此(或者如果我使用它,至少它不会给我预期的值,也

我需要在计算着色器中为数组的每个条目传递两个布尔值。现在,我将从cpu获取这些值,但稍后我将希望从在该值之前运行的另一个计算着色器生成这些值。我的工作原理如下:

使用
glm::bvec2
我可以将布尔值相对打包到内存中(bvec每字节存储一个布尔值。可能会更好,但现在就可以了,我总是可以手动打包)。然后,我使用
vkMapMemory
将数据放入Vulkan缓冲区(然后将其复制到设备本地缓冲区,但这可能与此无关)

不幸的是,GLSL的bvec2并不等同于此(或者如果我使用它,至少它不会给我预期的值,也许我做得不对?使用
bvec2 changes[]
会在以下代码中产生错误的结果。我怀疑对齐不匹配)。因此,计算着色器按如下方式访问此数组:

布局(绑定=2,标量)缓冲区更改 { uint变化[]; }; void main(){ //uint是4字节,glm::bvec2是2字节 uint changeIndex=gl_globalinJournalid.x/2; //记忆中的顺序似乎颠倒了: //v1(x1,y1)后跟v2(x2,y2)存储为:0000000(y2)0000000(x2)0000000(y1)0000000(x1) uint changeOffset=(总账全局假期ID.x%2)*16;
uint maskx=1由于
glm::bvec2
将布尔值存储为两个字节,因此可能由提供的显式8位无符号整数向量类型
u8vec2
在这里更方便?我不知道您使用的Vulkan驱动程序是否支持必要的功能(我假设它是
storageBuffer8BitAccess
)但是。

安德里亚的评论提到了一个有用的扩展:
GL_EXT_shader_8bit_storage
。 由于对布尔值的写入访问是并行完成的,紧凑封装的唯一选择是原子。我选择用内存效率换取性能,在一个字节中存储两个布尔值,“浪费”6位。代码如下:

#扩展GL_EXT_着色器_8bit_存储:启用
void getBools(输入uint数据、输出bool拆分、输出bool合并){
分割=(数据&1)>0;
合并=(数据&2)>0;
}
uint挫折工具(在布尔拆分、布尔合并中){
uint结果=0;
如果(分割)结果=结果| 1;
如果(合并)结果=结果| 2;
返回结果;
}
//用法:
布局(绑定=4,标量)缓冲区更改缓冲区
{
uint8_t变化[];
};
//[...]
布尔分裂,合并;
getBools(uint(变更[invocationIdx])、拆分、合并;
//[...]
变更[idx]=uint8_t(setBools(拆分、合并));

注意构造函数,扩展提供的数据类型不提供任何算术运算,必须在使用前进行转换。

“有没有更优雅的方法来实现这一点?”这里到底有什么不雅观的地方?@NicolBolas好吧,公平点,我想……我的意思是,是否有更好的数据类型可供选择,我是否可以以某种方式保存一些这些操作(尽管我猜位移位等相当快)等等。我的问题很模糊,因为我想如果有更好的东西,那么我就错过了一些明显的东西。我想以几乎没有额外成本的方式将布尔值按位打包是可能的。甚至模也可以按位进行,而且……是的,如果没有明显更好的替代方案,那么我想这非常有效我已经说过了。那么,我可能会发布我的最终代码作为答案。你可能会发现GPU驱动程序的着色器编译器仍然优化了数组。@Andrea真的吗?我意识到SPIRV是一个中间版本,但我没想到在这两者之间会有另一组优化。也就是说,我从NVIDIA NSight获得了着色器的代码-我假设不正确吗该工具提取完全编译的着色器代码并对其进行反编译吗?SPIR-V仍然比它编译的要高级得多,并且使用常量数组并不是一种罕见的模式,因此编译器显然希望在可以的情况下对其进行优化。对不起,我对NSight一无所知。不幸的是,我的上述解决方案不起作用,因为我本应该知道从一开始就不知道。这会导致竞争条件,因为每个uint32写入16次。如果其中任何一次都是并发的,再见数据。看起来您的8位存储扩展是节省空间的最佳方式,我已经成功尝试了。明天我应该会更新答案。感谢您建议扩展!