为什么这个使用 Metal 显示相机输出的 Xcode 项目对电池有如此大的影响,我怎样才能让它变得更好?

Why does this Xcode project using Metal to display camera output have so much impact on the battery, and how can I make it better?

我使用 CoreImageHelpers 作为使用 Metal 通过相机显示实时过滤输出的基础。问题是当我期望 Metal 的性能比更新 UIImageView 甚至 OpenGL 好得多时,我意外地受到了高电池影响。

更新:使用 my forked version

进行测试

在测试原始项目之前,请务必更新一些内容:

-在ImageView.swift中,draw()必须在commandBuffer.commit()

之后调用

-在 captureOutput 中将 DispatchQueue.main.async 环绕在 connection.videoOrientation 周围:

    DispatchQueue.main.async{
        connection.videoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue)!

    }

我正在 iPhone 6s Plus 上进行测试,在 Debug Navigator 中查看时,一个 CICMYKHalftone 效果将电池影响提高到很高。

我认为使用这个 Metal view 会极大地提高性能,但它似乎并没有,即使 运行 在 25-30 fps 的较低帧速率下也是如此。

是否有任何重要的缺失可以像其他实时相机效果应用程序一样提高电池使用率?

更新

我添加的另一个性能更新是 MTKView 的 preferredFramesPerSecond 设置,我将其设置为 30,因为默认情况下它每秒最多调用 60 次。我将其与较低的设备帧速率相结合,以实现更好的性能和更少的电池影响。

首先,由于您手动驱动绘图(通过调用 draw()),您应该将视图的 isPaused 属性 设置为 true。如果你不这样做,视图会在你调用它时和内部计时器上自行绘制。

其次,renderImage()draw()的关系是倒置的。 image didSet 观察者不应调用 renderImage()。它应该调用 draw()。您应该覆盖 draw(_ rect: CGRect) 来完成 renderImage() 的工作(减去对 draw() 的调用)。 (您可以让 draw(_ rect: CGRect) 调用 renderImage() 或者您可以简单地将 renderImage() 重命名为 draw(_ rect: CGRect)。)

根据您的具体需要,您还可以将 enableSetNeedsDisplay 设置为 true 并将 image didSet 更改为调用 setNeedsDisplay() 而不是 draw()。这会有更多的延迟,但会避免过于频繁地尝试绘制。