首页 > 解决方案 > 在 host->shader 和/或 shader->shader 之间传递 bvec2 数组

问题描述

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

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

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

layout (binding = 2, scalar) buffer Changes
{
    uint changes[];
};

void main() {
    //uint is 4 byte, glm::bvec2 is 2 byte
    uint changeIndex = gl_GlobalInvocationID.x / 2;

    //order seems to be reversed in memory: 
    //v1(x1, y1) followed by v2(x2, y2) is stored as: 0000000(y2) 0000000(x2) 0000000(y1) 0000000(x1) 
    uint changeOffset = (gl_GlobalInvocationID.x % 2) * 16;
    uint maskx = 1 << (changeOffset + 0);
    uint masky = 1 << (changeOffset + 8);

    uint uchange = changes[changeIndex];
    bvec2 change = bvec2(uchange & maskx, uchange & masky);
}

这行得通。进行了一些试验和错误,但我们走了。我现在有两个问题:

  1. 有没有更优雅的方法来做到这一点?
  2. 通过计算着色器生成值时,我不会使用 glm::bvec2。我是否应该手动将布尔值(每位一个)打包到 uint 中,还是有更好的方法?

在这个应用程序中,性能对我来说非常重要,因为我正在尝试对事物进行基准测试。内存使用优化是次要的,但也值得考虑。在优化 GLSL 方面相对缺乏经验,我很高兴您能给我的任何建议。

标签: glslvulkancompute-shader

解决方案


由于将布尔值存储为两个字节,也许扩展提供glm::bvec2的显式 8 位无符号整数向量类型在这里会更方便?不过,我不知道您使用的 Vulkan 驱动程序是否支持必要的功能(我假设它是)。u8vec2GL_EXT_shader_8bit_storagestorageBuffer8BitAccess


推荐阅读