私は Brad Larson による GPUImage ライブラリを使用していますが、興味深い問題を発見したと思います。
次のシェーダー プログラムは問題なく実行されます。
NSString *const kDilationFragmentShaderString = SHADER_STRING
(
precision highp float;
uniform int height;
uniform int width;
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform int radius;
void main (void)
{
vec2 uv = textureCoordinate;
vec2 theSize = vec2(width, height);
vec3 theMax = texture2D(inputImageTexture, uv).rgb;
gl_FragColor = vec4(theMax, 1.0);
}
);
ただし、このバージョンは大きな画像 (つまり、カメラからの 4x3 画像を最長辺 2560 にサイズ変更) でクラッシュします。私の考えでは、大きく異なるのは texture2D 呼び出しのセットだけです。
NSString *const kDilationFragmentShaderString = SHADER_STRING
(
precision highp float;
uniform int height;
uniform int width;
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform int radius;
void main (void)
{
vec2 uv = textureCoordinate;
vec2 theSize = vec2(width, height);
vec3 theMax = texture2D(inputImageTexture, uv).rgb;
int i;
int j;
int radsqr = radius*radius;
for (j = -radius; j <= radius; ++j) {
for (i = -radius; i <= radius; ++i) {
if (i * i + j * j > radsqr) continue;
theMax = max(theMax, texture2D(inputImageTexture, uv + vec2(i,j)/theSize).rgb);
}
}
gl_FragColor = vec4(theMax, 1.0);
}
);
このフィルターを実行してから、最小値を持つ 2 番目のフィルターを実行しています (つまり、形態学的膨張と浸食、または形態学的クローズ オペレーター)。
これを実装するためのより最適な方法は、頂点シェーダーを介してすべての texture2D 呼び出しを独自の場所に取得することです。ただし、半径が 10 の場合、314 個の頂点が必要になり、許可されている場所の数を超えてしまいます。これらをシミュレーターで実行し、他のすべてが等しい場合、最初のコードは問題なく終了しますが、2 番目のコードはメモリを爆発させ、浸食フィルターの呼び出しのためにメモリが劇的に増加します。iPhone 4s で実行すると、最初のコード フラグメントは問題なく (そしてもちろん非常に迅速に) 終了しますが、2 番目のコード フラグメントは拡張後にクラッシュし、侵食呼び出しを実行しません。
最初は、texture2D がリークしているように見えます。ただし、これらの関数はスレッドで呼び出されています。スレッドが終了すると、シミュレータですべてのメモリがクリアされます。その結果、関数は、最初に正しく機能する場合、問題なく複数回実行できます。
だから私の質問はこれです:この動作を引き起こす可能性のある texture2D 呼び出しは何ですか? 呼び出し間のスレッドの終了とは無関係に、フィルターが完了したら、作成されたバッファーをフラッシュする方法はありますか?
編集: この質問を投稿してから 1 週間で学んだこと: 問題は for ループ自体にあります。for ループを削除すると、メモリの問題はなくなります。あれは、
NSString *const kDilationFragmentShaderString = SHADER_STRING
(
precision highp float;
uniform int height;
uniform int width;
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
uniform int radius;
void main (void)
{
vec2 uv = textureCoordinate;
vec2 theSize = vec2(width, height);
vec3 theMax = texture2D(inputImageTexture, uv).rgb;
int i;
int j;
int radsqr = radius*radius;
for (j = -radius; j <= radius; ++j) {
for (i = -radius; i <= radius; ++i) {
}
}
gl_FragColor = vec4(theMax, 1.0);
}
);
ループ内で何かが起こっているかのように多くのメモリを割り当てます。シミュレーターのインスペクターでこの動作を決定しています。1280x1280 の画像で for ループを使用せずにシェーダーを実行すると、合計 202 MB が割り当てられ、for ループを使用して実行すると、for ループ内で何が起こっても、230 MB が割り当てられます。while ループでも同じ動作が発生します。