Ios 关于CIContext、OpenGL和Metal(SWIFT)的混淆。CIContext默认使用CPU还是GPU?

Ios 关于CIContext、OpenGL和Metal(SWIFT)的混淆。CIContext默认使用CPU还是GPU?,ios,swift,opengl,metal,Ios,Swift,Opengl,Metal,因此,我正在制作一个应用程序,其中一些主要功能围绕着将CIFilters应用于图像 let context = CIContext() let context = CIContext(eaglContext: EAGLContext(api: .openGLES3)!) let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!) 所有这些都让我在CameraViewController上获得了相同的CPU使用率(70%

因此,我正在制作一个应用程序,其中一些主要功能围绕着将CIFilters应用于图像

let context = CIContext()
let context = CIContext(eaglContext: EAGLContext(api: .openGLES3)!)
let context = CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)
所有这些都让我在CameraViewController上获得了相同的CPU使用率(70%),我将过滤器应用于帧并更新imageview。所有这些似乎都以完全相同的方式工作,这让我觉得我遗漏了一些重要的信息

例如,使用AVFoundation,我从相机获取每一帧,应用过滤器并用新图像更新imageview

let context = CIContext()

func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
    connection.videoOrientation = orientation
    connection.isVideoMirrored = !cameraModeIsBack
    let videoOutput = AVCaptureVideoDataOutput()
    videoOutput.setSampleBufferDelegate(self, queue: DispatchQueue.main)

    let sharpenFilter = CIFilter(name: "CISharpenLuminance")
    let saturationFilter = CIFilter(name: "CIColorControls")
    let contrastFilter = CIFilter(name: "CIColorControls")
    let pixellateFilter = CIFilter(name: "CIPixellate")

    let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer)
    var cameraImage = CIImage(cvImageBuffer: pixelBuffer!)

    saturationFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
    saturationFilter?.setValue(saturationValue, forKey: "inputSaturation")
    var cgImage = context.createCGImage((saturationFilter?.outputImage!)!, from: cameraImage.extent)!
    cameraImage = CIImage(cgImage: cgImage)

    sharpenFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
    sharpenFilter?.setValue(sharpnessValue, forKey: kCIInputSharpnessKey)
    cgImage = context.createCGImage((sharpenFilter?.outputImage!)!, from: (cameraImage.extent))!
    cameraImage = CIImage(cgImage: cgImage)

    contrastFilter?.setValue(cameraImage, forKey: "inputImage")
    contrastFilter?.setValue(contrastValue, forKey: "inputContrast")
    cgImage = context.createCGImage((contrastFilter?.outputImage!)!, from: (cameraImage.extent))!
    cameraImage = CIImage(cgImage: cgImage)

    pixellateFilter?.setValue(cameraImage, forKey: kCIInputImageKey)
    pixellateFilter?.setValue(pixelateValue, forKey: kCIInputScaleKey)
    cgImage = context.createCGImage((pixellateFilter?.outputImage!)!, from: (cameraImage.extent))!
    applyChanges(image: cgImage)

}
另一个例子是如何将更改仅应用于普通图像(我使用滑块进行所有这些操作)

差不多:

  • 从UiImg创建CgImg
  • 从CgImg创建CiImg
  • 使用上下文应用过滤器并转换回UiImg
  • 使用新UiImg更新任何视图
  • 这在我的iPhoneX上运行得很好,在我的iPhone6上也运行得很好。因为我的应用程序非常完整,所以我希望尽可能地优化它。我已经阅读了很多关于使用OpenGL和Metal来做事情的文档,但似乎不知道如何开始


    我一直认为我是在CPU上运行这些进程,但是用OpenGL和Metal创建上下文并没有带来任何改进。我是否需要使用MetalKit视图或GLKit视图(eaglContext似乎完全不推荐)?我该怎么翻译呢?苹果的文档似乎很平淡。

    我开始对此发表评论,但我认为自WWDC'18以来,这是最好的答案。我会像其他人一样编辑而不是评论,如果这样做是正确的,我愿意删除整个答案

    你在正确的轨道上-尽可能利用GPU,这是一个很好的选择。CoreImage和Metal虽然“通常”使用GPU的“低级”技术,但如果需要,也可以使用CPU。核心图形?它使用GPU呈现事物

    图像。
    UIImage
    CGImage
    是实际图像。但是,
    CIImage
    不是。最好的思考方法是为一个图像制作“配方”

    在使用过滤器时,我通常会坚持使用CoreImage、
    CIFilters
    、CIImages和
    GLKViews
    。对CIImage使用GLKView意味着使用
    OpenGL
    和单个
    CIContext
    EAGLContext
    。它提供的性能几乎与使用
    MetalKit
    MTKViews
    一样好

    至于使用
    UIKit
    ,它是
    UIImage
    UIImageView
    ,我只在需要的时候做——保存/共享/上传,随便什么。在那之前,请坚持使用GPU

    这就是它开始变得复杂的地方

    Metal是苹果专有的API。因为他们拥有硬件——包括CPU和GPU——他们已经为他们进行了优化。它的“管道”与OpenGL有些不同。没什么大不了的,只是不同而已

    在WWDC'18之前,使用
    GLKit
    ,包括
    GLKView
    ,都是不错的。但OpenGL的所有东西都被抹黑了,苹果公司正在将这些东西转移到金属上。虽然性能提升(目前)并不是很好,但您最好使用新的工具来使用MTKView、Metal和CIContext`


    请看@matt给出的答案,了解如何使用MTKViews。

    一些独立的观点:

    • 分析你的应用程序,找出它在哪里花费CPU时间
    • 如果图形工作实际上不是很难-也就是说,如果你的应用程序不受GPU限制-优化GPU工作可能无助于整体性能
    • 尽量避免在CPU和GPU之间来回移动数据。不要为每个过滤器输出持续创建
      CGImage
      s。核心图像的一个主要特征是,不必对每个效果进行渲染,然后一次渲染所有效果。此外,正如dfd在他的回答中所说,如果您直接渲染到屏幕,而不是创建一个
      UIImage
      以显示在图像视图中,那会更好
    • 避免重复工作。不要每次都重新创建
      CIFilter
      对象。如果参数没有改变,不要每次都重新配置它们

    是的,我刚刚意识到我没有有效地链接或创建过滤器,谢谢!有趣的是,我实现了MetalKitView,在我的iPhoneX上,我已经将cpu负载减少了约35%,但在我的iPhone6上,这太糟糕了。在渲染到mtkView时,它只使用大约17%的cpu,这非常容易出错。理论上性能更好,但在实践中无法使用。@RahishMontegomery我有相反的问题。我的iPhone 6s Plus性能很好,电池电量低,但我的iPhone XS在电池电量高的情况下性能更差,即使通过相机拍摄的图像和两部手机渲染的图像大小相同。感谢您的资源!我成功地实现了我想用它做的事情。在我的iphoneX上给了我很好的性能,但是在我的iphone6上运行的mtkView无法使用!通过每秒30次将图像渲染到imageview,我获得了更好的用户体验。看起来是iPhone6中A8芯片的一个缺陷。很高兴我帮了忙。至于iphone6呢?在一个月内,我们将落后三代人。是的,我真的希望苹果能保持更多的一致性。。。但我想这就是我们付出的代价。
       func imagePixelate(sliderValue: CGFloat){
        let cgImg = image?.cgImage
        let ciImg = CIImage(cgImage: cgImg!)
        let pixellateFilter = CIFilter(name: "CIPixellate")
        pixellateFilter?.setValue(ciImg, forKey: kCIInputImageKey)
        pixellateFilter?.setValue(sliderValue, forKey: kCIInputScaleKey)
        let outputCIImg = pixellateFilter?.outputImage!
        let outputCGImg = context.createCGImage(outputCIImg!, from: (outputCIImg?.extent)!)
        let outputUIImg = UIImage(cgImage:outputCGImg!, scale:(originalImage?.scale)!, orientation: originalOrientation!)
        imageSource[0] = ImageSource(image: outputUIImg)
        slideshow.setImageInputs(imageSource)
        currentFilteredImage = outputUIImg
    }