Search code examples
glslvulkan

In a Vulkan compute shader can you pass a buffer to a function?


Argument to Vulkan compute shaders are like "globals" in the shader source

layout(binding = 0) buffer storageBuffer1 {
    float data1[];
}

layout(binding = 1) buffer storageBuffer2 {
    float data2[];
}

Supposing I had a function foo(float arg[]) {...} that does some heavy lifting and I wanted to use on both data1 and data2, how can I pass the data to foo?:

void foo(/*something*/)
{
    // Tricky stuff.
}

void main()
{
    foo(data1);
    foo(data2);
}

The GLSL compiler says an array argument to foo

void foo(float x[])
{
}

needs a compile-time constant size and I might not know that.


Solution

  • GLSL is very value-oriented; you can't pass a pointer to an array to a function. You can pass an array, but it is conceptually passed via copying all of the elements from the given array into the parameter array. This is important, as the compiler will likely generate different code to access a global resource than to access a local array. GLSL hides these issues by not letting you get a "pointer" to anything.

    SPIR-V is able to be less value-oriented, but the logical addressing mode of SPIR-V that Vulkan uses makes using pointers to array resources equally difficult.

    The best you can do is make an array of storage buffers and pass an integer to the function telling it when array element to use:

    layout(binding = 0) buffer storageBuffers
    {
        float data[];
    } elements[2];
    
    void foo(int index)
    {
      elements[index].data[whatever];
    }
    

    But the implementation may not allow non-constant expressions to index arrays of storage buffers. You'll have to check the implementation's feature set to find out if you can do this.