Ios 关于CIContext、OpenGL和Metal(SWIFT)的混淆。CIContext默认使用CPU还是GPU?
因此,我正在制作一个应用程序,其中一些主要功能围绕着将CIFilters应用于图像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%
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)
}
另一个例子是如何将更改仅应用于普通图像(我使用滑块进行所有这些操作)
差不多:
我一直认为我是在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之间来回移动数据。不要为每个过滤器输出持续创建
s。核心图像的一个主要特征是,不必对每个效果进行渲染,然后一次渲染所有效果。此外,正如dfd在他的回答中所说,如果您直接渲染到屏幕,而不是创建一个CGImage
以显示在图像视图中,那会更好UIImage
- 避免重复工作。不要每次都重新创建
对象。如果参数没有改变,不要每次都重新配置它们CIFilter
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
}