glsl 函数指针(或等价物)
glsl function pointer (or equivalent)
我正在尝试根据变量的值调用许多函数之一。该变量是在运行时设置的,因此 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 没有函数指针。甚至 SPIR-V 也没有函数指针。着色器代表一个有限的执行环境。其中一个限制是不需要堆栈。如果没有其中之一,你就不能真正拥有任意函数指针。
GLSL 4.00 的非常不明智的1 shader subroutines 功能可能也无济于事。仅当您的 <something calculated during runtime>
是 CPU 生成的值时才会有所帮助,而在您的情况下这似乎不太可能。
唯一的通用解决方案是 switch 语句。坦率地说,这没有错。
我的意思是,无论如何,你已经通过这种情况彻底扼杀了你的表现。不管它是如何实现的,如果同一个波前中的不同实例正在执行不同的代码,那么你在性能方面就有点搞砸了。
更不用说,根据有多少条件,switch 语句不一定会变慢。它如何实现完全取决于硬件。如果可以使用跳转表,则可以相当高效地完成(当然忽略上述性能问题)。
此外,还有三十二上校的想法,您将每个函数的运算编码为具有常数向量的点积。显然,这限制了您的各种功能实际可以执行的内容。但如果它适用于你的情况,它就有效。
1 如果你想反驳这一点,请考虑 SPIR-V 提供了对 GLSL 的每个功能的模拟,无论多么冗余、愚蠢或不必要......除了着色器子程序。
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;
}
这些“函数指针”可以用来模拟higher-order functions in GLSL。
我正在尝试根据变量的值调用许多函数之一。该变量是在运行时设置的,因此 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 没有函数指针。甚至 SPIR-V 也没有函数指针。着色器代表一个有限的执行环境。其中一个限制是不需要堆栈。如果没有其中之一,你就不能真正拥有任意函数指针。
GLSL 4.00 的非常不明智的1 shader subroutines 功能可能也无济于事。仅当您的 <something calculated during runtime>
是 CPU 生成的值时才会有所帮助,而在您的情况下这似乎不太可能。
唯一的通用解决方案是 switch 语句。坦率地说,这没有错。
我的意思是,无论如何,你已经通过这种情况彻底扼杀了你的表现。不管它是如何实现的,如果同一个波前中的不同实例正在执行不同的代码,那么你在性能方面就有点搞砸了。
更不用说,根据有多少条件,switch 语句不一定会变慢。它如何实现完全取决于硬件。如果可以使用跳转表,则可以相当高效地完成(当然忽略上述性能问题)。
此外,还有三十二上校的想法,您将每个函数的运算编码为具有常数向量的点积。显然,这限制了您的各种功能实际可以执行的内容。但如果它适用于你的情况,它就有效。
1 如果你想反驳这一点,请考虑 SPIR-V 提供了对 GLSL 的每个功能的模拟,无论多么冗余、愚蠢或不必要......除了着色器子程序。
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;
}
这些“函数指针”可以用来模拟higher-order functions in GLSL。