CIFilter似乎在GPU上失败

时间:2015-04-12 19:43:37

标签: ios gpu grand-central-dispatch core-image

这是一个奇怪的 - 我甚至不知道如何开始。

我正在使用CIFilter来模糊图像。以下是代码的本质,作为UIImage上的类别实现:

- (void)imageByApplyingBlur:(CGFloat)radius completion:(void (^)(UIImage *))completion {

  // If no completion, then nothing to do
  if (completion == nil) {
    return;
  }

  // If no radius, self is the result
  if (radius == 0.0) {
    completion(self);
    return;
  }

  UIApplicationState appState = [UIApplication sharedApplication].applicationState;
  CIImage *imageToBlur = [CIImage imageWithCGImage:self.CGImage];
  CGFloat scale = [UIScreen mainScreen].scale;

  // Do the thread-safe CIImage blurring on a high-priority concurrent thread.
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

    NSDictionary *contextOptions = nil;

    // Always include the kCIContextPriorityRequestLow : @(YES) pair, because
    // otherwise, the foreground animation framerate suffers while blurring.
    if (appState == UIApplicationStateBackground) {
      contextOptions = @{
                         kCIContextPriorityRequestLow  : @(YES),
                         // If we're not active, force CIContext to use the CPU renderer
                         // CPU rendering should be allowed even in the background
                         kCIContextUseSoftwareRenderer : @(YES)
                         };
    } else {
      contextOptions = @{
                         kCIContextPriorityRequestLow  : @(YES),
                         };
    }

    CIContext *context = [CIContext contextWithOptions:contextOptions];

    CIFilter *gaussianBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
    [gaussianBlurFilter setValue:imageToBlur forKey:@"inputImage"];
    [gaussianBlurFilter setValue:@(radius) forKey:@"inputRadius"];

    CIImage *resultImage = [gaussianBlurFilter valueForKey:@"outputImage"];

    CGRect cropRect = {
      .origin.x = radius,
      .origin.y = radius,
      .size.width = (imageToBlur.extent.size.width - (2 * radius)),
      .size.height = (imageToBlur.extent.size.height - (2 * radius))
    };

    // Crop transparent edges from blur
    resultImage = [resultImage imageByCroppingToRect:cropRect];

    // Generate returnable UIImage (important to make the image "from" a CGImage, not a CIImage)
    CGImageRef resultCGImage = [context createCGImage:resultImage fromRect:resultImage.extent];
    UIImage *resultUIImage = [UIImage imageWithCGImage:resultCGImage
                                                 scale:scale
                                           orientation:UIImageOrientationUp];
    CGImageRelease(resultCGImage);

    // The completion block has to happen on the main thread
    dispatch_async(dispatch_get_main_queue(), ^{
      completion(resultUIImage);
    });
  });
}

大约90%的时间,这种方法完美无瑕。但是,有时,它从不向回调块提交有效图像,我看到了一个令人难以置信的错误日志。错误日志很长,所以我会等到问题结束后复制粘贴它。

一些注意事项:

  • 在模糊并发调度队列之前,我同步模糊了。这很慢,但我从未见过这种问题。可能是代码中的某些东西在队列中同时发生并不正常吗?当我的应用程序启动时,它使用此方法提交两个图像模糊,这是我唯一一次注意到该方法无法正常工作。

  • This question talks about requirements for using CIFilter from multiple threads safely,但就我所知,我满足了这些要求。理论上我可以为此移动到一个串行队列,但我不明白为什么这一定会有所帮助。

  • 我得到的错误真的奇怪 - 我不太了解CoreImage如何在内部工作,但这看起来像应该编译为在GPU上执行的代码是以某种方式无效。但只有部分时间?我真的很难过。

那么,我的问题是怎么回事?理想情况下,我该如何解决?

当我没有图像时,下面是相关的日志输出:

liblib:3:15: error: :unkown type or function name: 'mix'
3:15: error: unkown type or function name: 'mix'
    return mix(y, z, step(0.0,x));
              ^
    return mix(y, z, step(0.0,x));
              ^
lib:lib:1:16:6:: error : error: non-void function should return a value
non-void function should return a value
vec4 compare (vec4 x, vec4 y, vec4 z)
     ^
vec4 compare (vec4 x, vec4 y, vec4 z)
     ^
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
    return tan(x);
           ^~~
           tan_
lib:51:26: error: unkown type or function name: 'max'
    return vec4(s.rgb/max(s.a,0.00001), s.a);
                         ^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
     ^
lib:56:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                           ^
lib:62:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                           ^
filter:4:12: error: unkown type or function name: 'clamp'
  x = clamp(min(x, x.yzwx), 0.0, 1.0);
           ^
filter:1:55: error: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                      ^
filter:1:6: error: non-void function should return a value
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
    return tan(x);
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
     ^
           ^~~
           tan_
filter:3:26: error: unkown type or function name: 'mix'
lib:51:26: error: unkown type or function name: 'max'
  s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                         ^
    return vec4(s.rgb/max(s.a,0.00001), s.a);
                         ^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
     ^
lib:56:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                           ^
lib:62:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                           ^
lib:3:15: error: unkown type or function name: 'mix'
    return mix(y, z, step(0.0,x));
              ^
lib:1:6: error: non-void function should return a value
vec4 compare (vec4 x, vec4 y, vec4 z)
     ^
filter:4:12: error: unkown type or function name: 'clamp'
  x = clamp(min(x, x.yzwx), 0.0, 1.0);
           ^
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
filter:1:    return tan(x);
55:           ^~~ 
           tan_error
: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                      ^
libfilter::511::266::  errorerror: : unkown type or function name: 'max'
non-void function should return a value
    return vec4(s.rgb/max(s.a,0.00001), s.a);
                         ^
lib:49:vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }6
:     ^
 error: non-void function should return a value
vec4 unpremultiply (vec4 s)
     ^
filter:3:26: error: unkown type or function name: 'mix'
lib:56:28: error: unkown type or function name: 'mix'
  s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                         ^
    s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                           ^
lib:62:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                           ^
lib:3:15: error: unkown type or function name: 'mix'
    return mix(y, z, step(0.0,x));
              ^
filter:lib1:1:6::55: error : error: unkown type or function name: 'max'non-void function should return a value

vec4 compare (vec4 x, vec4 y, vec4 z)
     ^
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                      ^
filter:1:6: error: non-void function should return a value
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
     ^
filter:3:26: error: unkown type or function name: 'mix'
lib:24:12: error: unkown type or function name 'tan'; did you mean 'tan_'?
  s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));    return tan(x);

                         ^
           ^~~
           tan_
filter:1:47: error: unkown type or function name: 'clamp'
lib:51:26: errorvec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
                                              ^
filter:1:6: error: non-void function should return a value
: unkown type or function name: 'max'
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
     ^
    return vec4(s.rgb/max(s.a,0.00001), s.a);
                         ^
lib:49:6: error: non-void function should return a value
vec4 unpremultiply (vec4 s)
     ^
lib:56:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*0.077399380804954, pow(abs(s.rgb)*0.947867298578199 + 0.052132701421801, vec3(2.4)), step(0.04045, abs(s.rgb)));
                           ^
lib:62:28: error: unkown type or function name: 'mix'
    s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                           ^
filter:1:55: error: unkown type or function name: 'max'
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
                                                      ^
filter:1:6: error: non-void function should return a value
vec4 _ci_unpremultiply(vec4 s) { return vec4(s.rgb/max(s.a,0.00001), s.a); }
     ^
filter:3:26: error: unkown type or function name: 'mix'
  s.rgb = sign(s.rgb)*mix(s.rgb*12.92, pow(abs(s.rgb), vec3(0.4166667)) * 1.055 - 0.055, step(0.0031308, abs(s.rgb)));
                         ^
filter:1:47: error: unkown type or function name: 'clamp'
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
                                              ^
filter:1:6: error: non-void function should return a value
vec4 _ci_clamp_to_alpha(vec4 s) { return clamp(s, 0.0, s.a); }
     ^
ERROR - could not find uniform for argument 0
ERROR - could not find uniform for argument 0
ERROR - could not find uniform for argument 1
ERROR - could not find uniform for argument 1
ERROR - could not find uniform for argument 2
ERROR - could not find uniform for argument 2
ERROR - could not find uniform for argument 3
ERROR - could not find uniform for argument 3

2 个答案:

答案 0 :(得分:0)

这与您的主要问题无关,但有一种更好的方法可以“从模糊中裁剪透明边缘”。试试这个:

CGRect originalExtent = img.extent;
img = [img imageByClampingToExtent:originalExtent];
img = [img imageByApplyingFilter:@"CIGaussianBlur"
                          params:@{@"inputRadius" : @(radius)}];
img = [imageByCroppingToRect:originalExtent]

答案 1 :(得分:-1)

虽然它不是错误的解决方案,但我绝对推荐GPUImage用于GPU绑定图像操作,其中包括非常快速的高斯模糊滤镜。