我试图根据变量的值调用许多函数之一。变量在运行时设置,因此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);
}
答案 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;
}