【问题标题】: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?为什么这个 Xcode 项目使用 Metal 来显示相机输出对电池有这么大的影响,我怎样才能让它变得更好?
【发布时间】:2023-03-26 23:35:01
【问题描述】:

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

更新:使用my forked version 进行测试,或者

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

-在ImageView.swift中,draw()必须在commitBuffer.commit()之后调用

-在 captureOutput 中围绕 connection.videoOrientation 包装 DispatchQueue.main.async:

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

    }

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

我认为使用此 Metal 视图会极大地提高性能,但似乎并没有,即使以 25-30 fps 的较低帧速率运行。

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

更新

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

【问题讨论】:

  • 为什么你希望 Metal 比更新 UIImageView 或使用 OpenGL 更快? CPU 和 GPU 上的工作负载对于所有这些都是相同的。 Metal 的开销比 OpenGL 少,但如果您使用 Metal,GPU 的计算能力和内存带宽不会神奇地改变。 (如果 Metal 的性能比 UIImageView 或 OpenGL 差得多,那当然是出了问题。)
  • 由于我使用 CIFilters 过滤图像,因此有必要在从像素缓冲区获取图像后立即创建 CIImage。实现 Metal 可以让我更快地将图像渲染到视图上,而无需先转换为 CGImage。 Metal 比 OpenGL 更优化,我已经比较了影响。这与性能无关,更多的是关于电池的影响。

标签: swift performance camera metal battery


【解决方案1】:

首先,由于您是手动驱动绘图(通过调用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()。这将有更多的延迟,但会避免尝试过于频繁地绘制。

【讨论】:

  • 谢谢 Ken - 除了第一个建议,我想我什么都懂。你的意思是我应该将 MetalImageView 的 paused 属性设置为 true 吗?我没有看到那个属性。
  • pausedMTKView 的属性。 MetalImageView 继承它。
  • 对不起,isPaused。它在 Objective-C 中称为paused
  • 所以你已经限制了视图的显示频率。 AVCapture 多久为您发送一次帧?它可能比需要更频繁地这样做。此外,在CameraCaptureHelper.captureOutput 中,您正在滥用调度。首先,只将实际需要在主线程上完成的事情分流到主队列。查询UIApplication.shared.statusBarOrientation 可以,设置connection.videoOrientation 不行。此外,该块必须是同步的,而不是异步的。调用 newCameraImage 可能只是主线程,但创建 CIImage 不是。
  • 我相信您应该从调用captureOutput 的线程上的像素缓冲区创建CIImage,然后在主线程上调用newCameraImage。因此,您可以将当前的一个语句一分为二。
猜你喜欢
  • 1970-01-01
  • 2011-04-22
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多