glsl 函数指针(或等效函数)

问题描述 投票:0回答:2

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

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

伪代码示例:

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);
}
glsl function-pointers raytracing
2个回答
12
投票

GLSL 没有函数指针。甚至SPIR-V也没有函数指针。着色器代表有限的执行环境。这些限制之一是缺乏对堆栈的要求。如果没有其中之一,你就不可能真正拥有任意函数指针。

GLSL 4.00 的

可怕的错误建议1着色器子例程功能可能也无济于事。仅当您的

<something calculated during runtime>
是 CPU 生成的值时才会有帮助,而这在您的情况下似乎不太可能。

唯一通用的解决方案是 switch 语句。坦率地说,这没有什么问题。

我的意思是,无论如何,你这样做都会彻底毁掉你的表现。无论它如何实现,如果同一波前中的不同实例正在执行单独的代码,那么性能方面就会有点糟糕。

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

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

1 如果您想对此提出异议,请考虑 SPIR-V 提供了 GLSL 的每个功能的模拟,无论多么冗余、愚蠢或不必要......除了着色器子例程。


1
投票

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

struct functions_list {
    int sin;
    int cos;
    int tan;
    int fract;
};
const 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;
}

这些“函数指针”可用于模拟 GLSL 中的高阶函数

© www.soinside.com 2019 - 2024. All rights reserved.