使用OpenGL ES 2着色器重新实现GLImageProcessing的性能问题

时间:2013-04-01 22:01:33

标签: ios opengl-es fragment-shader

我使用OpenGL ES 2着色器重新实现了Apple的GLImageProcessing。效果很完美,但Sharpness滤镜的性能不是很好 - 它只能以20 FPS运行。

着色器代码很简单:

  1. 传递0表示水平模糊。
  2. 传递1以进行垂直模糊。
  3. 传递2以将模糊纹理与原始纹理混合。
  4. 基本上,Pass 2中的纹理混合是缓慢的原因,因为Pass 0和Pass 1只进行一次而且不会导致性能不佳。

    如何改善表现?

    顶点着色器:

    attribute vec4 a_position;
    attribute vec2 a_texCoord;
    
    varying highp vec2 v_texCoord;
    varying highp vec2 v_texCoord1;
    varying highp vec2 v_texCoord2;
    varying highp vec2 v_texCoord1_;
    varying highp vec2 v_texCoord2_;
    
    uniform mat4 u_modelViewProjectionMatrix;
    uniform lowp int u_pass;
    
    const highp float blurSizeH = 1.0 / 320.0;
    const highp float blurSizeV = 1.0 / 480.0;
    
    void main()
    {
        v_texCoord = a_texCoord;
        if (u_pass == 0) {
            v_texCoord1 = a_texCoord + vec2(1.3846153846 * blurSizeH, 0.0);
            v_texCoord1_ = a_texCoord - vec2(1.3846153846 * blurSizeH, 0.0);
            v_texCoord2 = a_texCoord + vec2(3.2307692308 * blurSizeH, 0.0);
            v_texCoord2_ = a_texCoord - vec2(3.2307692308 * blurSizeH, 0.0);
        } else if (u_pass == 1) {
            v_texCoord1 = a_texCoord + vec2(0.0, 1.3846153846 * blurSizeV);
            v_texCoord1_ = a_texCoord - vec2(0.0, 1.3846153846 * blurSizeV);
            v_texCoord2 = a_texCoord + vec2(0.0, 3.2307692308 * blurSizeV);
            v_texCoord2_ = a_texCoord - vec2(0.0, 3.2307692308 * blurSizeV);
        }
    
        gl_Position = u_modelViewProjectionMatrix * a_position;
    }
    

    片段着色器:

    varying highp vec2 v_texCoord;
    varying highp vec2 v_texCoord1;
    varying highp vec2 v_texCoord2;
    varying highp vec2 v_texCoord1_;
    varying highp vec2 v_texCoord2_;
    
    uniform lowp int u_pass;
    uniform sampler2D u_texture;
    uniform sampler2D u_degenTexture;
    uniform mediump mat4 u_filterMat;
    
    void main()
    {
        if (u_pass == 0) {
            gl_FragColor = texture2D(u_texture, v_texCoord) * 0.2270270270;
            gl_FragColor += texture2D(u_texture, v_texCoord1) * 0.3162162162;
            gl_FragColor += texture2D(u_texture, v_texCoord1_) * 0.3162162162;
            gl_FragColor += texture2D(u_texture, v_texCoord2) * 0.0702702703;
            gl_FragColor += texture2D(u_texture, v_texCoord2_) * 0.0702702703;
        } else if (u_pass == 1) {
            gl_FragColor = texture2D(u_degenTexture, v_texCoord) * 0.2270270270;
            gl_FragColor += texture2D(u_degenTexture, v_texCoord1) * 0.3162162162;
            gl_FragColor += texture2D(u_degenTexture, v_texCoord1_) * 0.3162162162;
            gl_FragColor += texture2D(u_degenTexture, v_texCoord2) * 0.0702702703;
            gl_FragColor += texture2D(u_degenTexture, v_texCoord2_) * 0.0702702703;
        } else {
            gl_FragColor = u_filterMat * texture2D(u_texture, v_texCoord) + (mat4(1.0) - u_filterMat) * texture2D(u_degenTexture, v_texCoord);
        }
    }
    

2 个答案:

答案 0 :(得分:1)

在继续这个之前,我建议你看看我的开源GPUImage项目吗?我在那里有几个手动优化的锐化效果,包括你在这里尝试的非锐化面具。我也很容易吸引图像和视频资源。

对于您的具体问题,有几个原因导致着色器运行速度低于预期。首先,您在片段着色器中使用分支。这会杀死iOS设备上的性能,如果可能的话应该避免。如果您确实需要为不同的传递设置不同的条件,请将它们拆分为单独的着色器程序,并根据需要交换程序,而不是使用统一控制流程。

我也不确定反复写入gl_FragColor是你能在这里做的最快的事情。我将使用lowp或mediump中间颜色变量,将高斯分量添加到其中,然后在完成时将最终结果写入gl_FragColor。

我确实看到你已经将采样偏移计算移动到顶点着色器,然后将这些偏移传递到片段着色器,这是人们通常会错过的好东西。一旦你实现了上面的调整(或者试着让我的框架看看我是如何处理这个),你应该从过滤中获得更好的结果。

答案 1 :(得分:1)

事实证明这很简单。性能不佳的原因是矩阵向量乘法:

varying highp vec2 v_texCoord;

uniform sampler2D u_texture;
uniform sampler2D u_degenTexture;
uniform lowp float u_filterValue;

void main()
{
    gl_FragColor = u_filterMat * texture2D(u_texture, v_texCoord) + (mat4(1.0) - u_filterMat) * texture2D(u_degenTexture, v_texCoord);
}

我最初使用矩阵编写代码,这样我的所有过滤器都可以共享相同的颜色混合代码。现在我学到了这一课,我只是回过头来编写特定于过滤器的代码并尽可能地使用标量操作:

varying highp vec2 v_texCoord;

uniform sampler2D u_texture;
uniform sampler2D u_degenTexture;
uniform lowp float u_filterValue;

void main()
{
    gl_FragColor = u_filterValue * texture2D(u_texture, v_texCoord) + (1.0 - u_filterValue) * texture2D(u_degenTexture, v_texCoord);
}

现在它真棒60 fps!

从来没有想过这是一个如此天真的问题,但确实如此。