Android Opengl:gl_FragColor的替代值

Android Opengl:gl_FragColor的替代值,android,opengl-es,glsl,glsles,Android,Opengl Es,Glsl,Glsles,我正在编写一个Android应用程序,它利用opengl对相机输出进行一些更改。我以这样一种方式编写代码,最终找出了导致性能问题的原因 #extension GL_OES_EGL_image_external : require precision mediump float; uniform samplerExternalOES sTexture; uniform vec4 vColor; const int MAX_COLORS = 6; uniform float vHues[MAX_CO

我正在编写一个Android应用程序,它利用opengl对相机输出进行一些更改。我以这样一种方式编写代码,最终找出了导致性能问题的原因

#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES sTexture;
uniform vec4 vColor;
const int MAX_COLORS = 6;
uniform float vHues[MAX_COLORS];
uniform float vOffsets[MAX_COLORS];
varying vec2 v_CamTexCoordinate;

float rgb2hue(vec4 c) {
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return abs(q.z + (q.w - q.y) / (6.0 * d + e));
}

bool isInRange(float a1,float a2, float vOffset) {
    if(a2 < 0.0) {
        return false;
    } else if(abs(a1-a2) < vOffset) {
        return true;
    } else if( a1 > a2) {
        return (1.0 - a1 + a2) < vOffset;
    } else {
        return (1.0 + a1 - a2) < vOffset;
    }
}

vec4 getGrey(vec4 c) {
    float grey = (c.r + c.g + c.b) / 3.0;
    return vec4(grey, grey, grey, c.a);
}

void main() {
    vec4 c = texture2D(sTexture, v_CamTexCoordinate);
    bool hasColor = vHues[0] >= 0.0;
    float hue = rgb2hue(c);
    vec4 test = getGrey(c);
    for(int i=0; i < MAX_COLORS; i++) {
       if(isInRange(hue, vHues[i], vOffsets[i])) {
          //If I uncomment this line the performance gets terrible
          //test = c;
       }
    }
    gl_FragColor = test;
}
#扩展GL#OES#EGL#U图像#U外部:需要
精密中泵浮子;
均匀的外部结构;
均匀vec4彩色;
const int MAX_COLORS=6;
均匀浮动颜色[最大颜色];
均匀浮动vOffsets[最大颜色];
可变矢量2 v_坐标;
浮动RGB2色调(vec4 c){
vec4k=vec4(0.0,-1.0/3.0,2.0/3.0,-1.0);
vec4p=mix(vec4(c.bg,K.wz),vec4(c.gb,K.xy),步骤(c.b,c.g));
vec4 q=混合(vec4(p.xyw,c.r),vec4(c.r,p.yzx),步骤(p.x,c.r));
浮动d=q.x-最小值(q.w,q.y);
浮子e=1.0e-10;
返回abs(q.z+(q.w-q.y)/(6.0*d+e));
}
布尔isInRange(浮点a1、浮点a2、浮点vOffset){
如果(a2<0.0){
返回false;
}否则如果(abs(a1-a2)a2){
返回(1.0-a1+a2)=0.0;
浮动色调=RGB2色调(c);
vec4试验=灰色(c);
对于(int i=0;i

当我取消对上面这行的注释时,对性能有很大的影响(跳过了很多帧)。我基本上想使用原始颜色有时和不同的颜色取决于某些条件。这是可行的,但有没有更有效的方法?还有,为什么这执行得如此糟糕?

当您注释掉这一行时,几乎可以肯定的是,您允许编译器删除整个循环,并将代码段缩减为:

gl_FragColor = getNewColor(color);
我想我们需要先看看MAX_COLORS、vColors和isValid函数的值,然后才能知道为什么性能如此差

通常,OpenGLES上片段着色器中的条件是坏消息。如果可能的话,用某种查找表(即可以采样的纹理)替换循环可以解决性能问题

这样做是否可行取决于你试图解决的问题,并且没有足够的背景

编辑:好的,现在发布了更多信息,我可以看到您的色调比较函数(isInRange)是一维的,非常适合更改为查找表。您应该考虑使用纹理查找替换整个循环。因此:

vec4 test = getGrey(c);
for(int i=0; i < MAX_COLORS; i++) {
   if(isInRange(hue, vHues[i], vOffsets[i])) {
      //If I uncomment this line the performance gets terrible
      //test = c;
   }
}
gl_FragColor = test;

毫无疑问,构建这样一个查找表是非常困难的,如果vhue和voffset一直在变化,那么查找表也需要一直在变化,这将对性能产生影响,但是我认为用纹理查找替换循环和所有条件的好处将是巨大的。

当你注释掉那一行时,你几乎肯定会允许编译器删除整个循环,并将代码段减少到:

gl_FragColor = getNewColor(color);
我想我们需要先看看MAX_COLORS、vColors和isValid函数的值,然后才能知道为什么性能如此差

通常,OpenGLES上片段着色器中的条件是坏消息。如果可能的话,用某种查找表(即可以采样的纹理)替换循环可以解决性能问题

这样做是否可行取决于你试图解决的问题,并且没有足够的背景

编辑:好的,现在发布了更多信息,我可以看到您的色调比较函数(isInRange)是一维的,非常适合更改为查找表。您应该考虑使用纹理查找替换整个循环。因此:

vec4 test = getGrey(c);
for(int i=0; i < MAX_COLORS; i++) {
   if(isInRange(hue, vHues[i], vOffsets[i])) {
      //If I uncomment this line the performance gets terrible
      //test = c;
   }
}
gl_FragColor = test;

毫无疑问,构建这样一个查找表是非常困难的,如果vhue和voffset一直在变化,那么查找表也需要一直在变化,这将对性能产生影响,但是我认为用纹理查找替换循环和所有条件的好处将是巨大的。

如果语句和分支通常是个坏主意,因为您的GPU无法正确优化。看见 更多细节。 你应该尽量避免分支,即使它意味着更多的计算

下面的代码应该可以做到这一点

//summarise your isInRange function
bool isInRange = a2 >= 0.0 && ((abs(a1-a2) < vOffset) || (1.0 - max(a1, a2) + min(a1, a2)) < vOffset); 

//this will be 0.0 if false and 1.0 if true
float isInRangef = float(isInRange);

//multiply by the float condition to set the value
gl_FragColor = isInRangef * c + (1.0 - isInRangef) * getGrey(c);
//总结您的isInRange函数
布尔isInRange=a2>=0.0&((abs(a1-a2)
作为一般公式

  • 将要分支的布尔值转换为浮点条件
  • 将目标值设置为
    (条件)*valueIfTrue+(1.0-条件)*valueIfFalse

如果声明和分支通常是个坏主意,因为您的GPU无法正确优化。看见 更多细节。 你应该尽量避免分支,即使它意味着更多的计算

下面的代码应该可以做到这一点

//summarise your isInRange function
bool isInRange = a2 >= 0.0 && ((abs(a1-a2) < vOffset) || (1.0 - max(a1, a2) + min(a1, a2)) < vOffset); 

//this will be 0.0 if false and 1.0 if true
float isInRangef = float(isInRange);

//multiply by the float condition to set the value
gl_FragColor = isInRangef * c + (1.0 - isInRangef) * getGrey(c);
//总结您的isInRange函数
布尔isInRange=a2>=0.0&((abs(a1-a2)
作为一般公式

  • 将要分支的布尔值转换为浮点条件
  • 将目标值设置为
    (条件)*valueIfTrue+(1.0-秒)