私はこれとまったく同じことを自分で行いましたが、ここで最適化できることがいくつかあります。
まず、enableTexture
条件を削除し、代わりにシェーダーを 2 つのプログラムに分割します。1 つは this の true 状態用で、もう 1 つは false 用です。iOS フラグメント シェーダー、特にテクスチャ読み取りを含むものでは、条件分岐は非常にコストがかかります。
次に、ここには 9 つの依存テクスチャ読み取りがあります。これらは、フラグメント シェーダー内でテクスチャ座標が計算されるテクスチャ読み取りです。依存テクスチャ読み取りは、iOS デバイス内の PowerVR GPU では非常にコストがかかります。これは、ハードウェアがキャッシュなどを使用してテクスチャ読み取りを最適化するのを妨げるためです。周囲の 8 つのピクセルと中央の 1 つのピクセルの固定オフセットからサンプリングしているため、これらの計算は次のようにする必要があります。頂点シェーダーに移動しました。これは、これらの計算をピクセルごとに実行する必要がなく、頂点ごとに 1 回実行するだけで、残りはハードウェア補間によって処理されることも意味します。
3 番目に、for() ループは、これまで iOS シェーダー コンパイラーによって適切に処理されていないため、可能な場合は回避する傾向があります。
前述したように、私はオープン ソースの iOS GPUImageフレームワークでこのような畳み込みシェーダーを作成しました。一般的な畳み込みフィルターには、次の頂点シェーダーを使用します。
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
uniform highp float texelWidth;
uniform highp float texelHeight;
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
void main()
{
gl_Position = position;
vec2 widthStep = vec2(texelWidth, 0.0);
vec2 heightStep = vec2(0.0, texelHeight);
vec2 widthHeightStep = vec2(texelWidth, texelHeight);
vec2 widthNegativeHeightStep = vec2(texelWidth, -texelHeight);
textureCoordinate = inputTextureCoordinate.xy;
leftTextureCoordinate = inputTextureCoordinate.xy - widthStep;
rightTextureCoordinate = inputTextureCoordinate.xy + widthStep;
topTextureCoordinate = inputTextureCoordinate.xy - heightStep;
topLeftTextureCoordinate = inputTextureCoordinate.xy - widthHeightStep;
topRightTextureCoordinate = inputTextureCoordinate.xy + widthNegativeHeightStep;
bottomTextureCoordinate = inputTextureCoordinate.xy + heightStep;
bottomLeftTextureCoordinate = inputTextureCoordinate.xy - widthNegativeHeightStep;
bottomRightTextureCoordinate = inputTextureCoordinate.xy + widthHeightStep;
}
および次のフラグメント シェーダー:
precision highp float;
uniform sampler2D inputImageTexture;
uniform mediump mat3 convolutionMatrix;
varying vec2 textureCoordinate;
varying vec2 leftTextureCoordinate;
varying vec2 rightTextureCoordinate;
varying vec2 topTextureCoordinate;
varying vec2 topLeftTextureCoordinate;
varying vec2 topRightTextureCoordinate;
varying vec2 bottomTextureCoordinate;
varying vec2 bottomLeftTextureCoordinate;
varying vec2 bottomRightTextureCoordinate;
void main()
{
mediump vec4 bottomColor = texture2D(inputImageTexture, bottomTextureCoordinate);
mediump vec4 bottomLeftColor = texture2D(inputImageTexture, bottomLeftTextureCoordinate);
mediump vec4 bottomRightColor = texture2D(inputImageTexture, bottomRightTextureCoordinate);
mediump vec4 centerColor = texture2D(inputImageTexture, textureCoordinate);
mediump vec4 leftColor = texture2D(inputImageTexture, leftTextureCoordinate);
mediump vec4 rightColor = texture2D(inputImageTexture, rightTextureCoordinate);
mediump vec4 topColor = texture2D(inputImageTexture, topTextureCoordinate);
mediump vec4 topRightColor = texture2D(inputImageTexture, topRightTextureCoordinate);
mediump vec4 topLeftColor = texture2D(inputImageTexture, topLeftTextureCoordinate);
mediump vec4 resultColor = topLeftColor * convolutionMatrix[0][0] + topColor * convolutionMatrix[0][1] + topRightColor * convolutionMatrix[0][2];
resultColor += leftColor * convolutionMatrix[1][0] + centerColor * convolutionMatrix[1][1] + rightColor * convolutionMatrix[1][2];
resultColor += bottomLeftColor * convolutionMatrix[2][0] + bottomColor * convolutionMatrix[2][1] + bottomRightColor * convolutionMatrix[2][2];
gl_FragColor = resultColor;
}
およびuniforms は入力画像の幅と高さの逆数であり、texelWidth
uniformは畳み込みのさまざまなサンプルの重みを指定します。texelHeight
convolutionMatrix
iPhone 4 では、これはカメラ ビデオの 640x480 フレームで 4 ~ 8 ミリ秒で実行されます。これは、その画像サイズで 60 FPS レンダリングを行うには十分です。エッジ検出などを行う必要がある場合は、上記を単純化し、プリパスで画像を輝度に変換してから、1 つのカラー チャネルからのみサンプリングすることができます。これはさらに高速で、同じデバイスでフレームあたり約 2 ミリ秒です。