opengl es -是否有一个内存泄漏通过texture2D在ios上的片段着色器



我正在使用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);
 }
);

这个版本,然而,崩溃的大图像(即,4 × 3的图像从相机调整到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);
 }
 );

我正在运行这个过滤器,然后是最小值的第二个过滤器(即形态膨胀,然后是侵蚀,或形态闭合操作符)。

我确实意识到实现这一点的更优方法是尝试通过顶点着色器将所有texture2D调用到自己的位置;然而,如果半径为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循环的shader时,我总共分配了202 mb,当我运行for循环时,我分配了230 mb,不管for循环内部发生了什么。同样的行为也发生在while循环中。

如果你想刷新东西,你可以调用glFlush(),它将刷新当前上下文的OpenGL命令队列。你可以做的另一件事是平铺你的图像,一次处理更小的部分。这就是像Photoshop, Final Cut Pro和其他应用程序的工作原理,它可以非常有效地节省内存。

最新更新