glsl函数指针(或等效的)

时间:2015-12-25 23:41:37

标签: glsl function-pointers raytracing

我试图根据变量的值调用许多函数之一。变量在运行时设置,因此CPU上的代码不起作用。由于存在大量可能性,使用if / switch语句会很慢。 [可能不正确]

我正在寻找一种方法来将函数存储在数组中,方法是使用函数指针,或者将实际的方程式(例如texcoord.x * 2)存储在数组中。

psuedo-code示例:

    in vec2 texcoord;
    out vec4 color;

    int number; //Assigned a number between 0 and 300 during runtime

    float func1(void) {
      return texcoord.x + texcoord.y;
    }

    float func2(void) {
      return texcoord.x*2;
    }

    ...

    float func299(void) {
      return texcoord.y - 7;
    }

    void main(void) {
      number = <something calculated during runtime>;
      float output = func<number>(); //              <--------------
      color = vec4(output, output, output, 1);
    }

2 个答案:

答案 0 :(得分:9)

GLSL没有函数指针。即使 SPIR-V 也没有函数指针。着色器代表有限的执行环境。其中一个限制是缺乏对堆栈的要求。如果没有其中任何一个,你就无法拥有任意的函数指针。

GLSL 4.00中可疑的 1 shader subroutines功能可能也无济于事。只有当您的<something calculated during runtime>是CPU生成的值时,它才有用,而且在您的情况下这似乎不太可能。

您拥有的唯一通用解决方案是switch语句。坦率地说,这并没有错。

我的意思是,无论如何,你已经绝对会通过这种情况来谋杀你的表现。无论它如何实现,如果同一个wavefront中的不同实例正在执行单独的代码,那么你就会在性能方面有所作为。

更不用说,根据有多少条件,switch语句不一定会变慢。如何实现完全取决于硬件。如果跳转表可用,则可以合理有效地完成(当然,忽略上述性能问题)。

此外,还有Thirty Two上校的想法,您可以将每个函数的操作编码为具有常量向量的点积。显然,这限制了您的各种功能实际执行的内容。但如果它适用于你的情况,那就有效。

1 如果你想对此提出质疑,请考虑SPIR-V为GLSL的每个功能提供模拟,无论多余,愚蠢或不必要......除了着色器子程序。

答案 1 :(得分:0)

GLSL中没有函数指针,但是可以用函数名称列表定义结构:

const struct functions_list {
    int sin;
    int cos;
    int tan;
    int fract;
};
functions_list functions = functions_list(1,2,3,4);

使用以下函数名称列表,可以模拟回调:

float callback(int func,float arg){
    if(func == functions.sin)
        return sin(arg);
    else if(func == functions.cos)
        return cos(arg);
    else if(func == functions.tan)
        return tan(arg);
    else if (func == functions.fract)
        return fract(arg);
    else
        return 0.0;
}