我正在使用 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);
}
);
我正在运行这个过滤器,然后是具有最小值的第二个过滤器(即,形态膨胀,然后是侵蚀,或形态闭合算子)。
我确实意识到实现这一点的更优化方法是尝试通过顶点着色器将所有纹理 2D 调用放到它们自己的位置;但是,如果半径为 10,则需要 314 个顶点,这超出了允许的位置数量。如果我在模拟器中运行这些并且所有其他条件都相同,那么第一个完成就好了,但是第二个代码会炸毁内存并且内存会急剧攀升以调用侵蚀过滤器。在 iPhone 4s 上运行,第一个代码片段完成得很好(当然,非常快),但第二个代码片段在膨胀后崩溃,并且不运行侵蚀调用。
最初,texture2D 看起来像是在泄漏;但是,这些函数是在一个线程中调用的。当线程退出时,模拟器中的所有内存都会被清除。因此,如果这些功能第一次正常工作,则可以多次运行而不会出现问题。
所以我的问题是:在那里进行的 texture2D 调用会导致这种行为吗?有没有办法在过滤器完成后刷新创建的任何缓冲区,而与结束调用之间的线程无关?
编辑:自从发布这个问题以来,我在一周内学到了一些东西:问题出在 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 循环运行它时,我得到 230 mb 分配,无论 for 循环内发生什么。while 循环也会发生相同的行为。