【问题标题】:glsl function pointer (or equivalent)glsl 函数指针(或等价物)
【发布时间】:2021-01-26 02:46:53
【问题描述】:

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

【问题讨论】:

  • “由于可能性很大,使用 if/switch 语句会很慢。”这是一个非常大胆的假设。
  • 如果你所有的函数都是线性方程,你可以创建一个向量数组,得到tex坐标和向量的点积。 (例如func1(texcoord) == dot(vec3(texcoord, 1), vec3(1,1,0))func299(texcoord) == dot(vec3(texcoord, 1), vec3(0, 1, -7))

标签: glsl function-pointers raytracing


【解决方案1】:

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

GLSL 4.00 的可怕的 il-advised1shader subroutines 功能可能也无济于事。仅当您的 &lt;something calculated during runtime&gt; 是 CPU 生成的值时才会有所帮助,而这在您的情况下似乎不太可能。

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

我的意思是,无论如何,你已经通过这种情况绝对会扼杀你的表现。不管它是如何实现的,如果同一波前中的不同实例执行不同的代码,那么你在性能方面有点搞砸了。

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

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

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

【讨论】:

【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-09-06
    • 2016-07-24
    • 1970-01-01
    • 1970-01-01
    • 2011-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多