I'm using CoreImageHelpers as a basis of using Metal to display live filtered output through the camera. The problem is that I unexpectedly get high battery impact, when I expect Metal to perform a lot better than updating a UIImageView or even OpenGL.
Update: Test with my forked version, OR
Before testing the original project, be sure to update a couple things:
-In ImageView.swift, draw() must be called after commandBuffer.commit()
-Wrap DispatchQueue.main.async around connection.videoOrientation in captureOutput:
DispatchQueue.main.async{
connection.videoOrientation = AVCaptureVideoOrientation(rawValue: UIApplication.shared.statusBarOrientation.rawValue)!
}
I'm testing on an iPhone 6s Plus, and the one CICMYKHalftone effect ramps the battery impact to high when viewing in the Debug Navigator.
I thought using this Metal view would drastically help performance, but it does not seem to, even when running at a lower frame rate of 25-30 fps.
Is there anything vital missing that would make battery usage better like other live camera effects apps?
Updates:
Another performance update I added is the MTKView's setting for preferredFramesPerSecond, which I set to 30, since it will by default call up to 60 times a second. I combine this with a lower device frame rate to achieve better performance and less battery impact.
First, since you're driving the drawing manually (by invoking draw()
), you should set the view's isPaused
property to true. If you don't do that, the view is drawing itself both when you call that and on an internal timer.
Second, the relationship between renderImage()
and draw()
is inverted. The image
didSet
observer should not call renderImage()
. It should call draw()
. You should have an override of draw(_ rect: CGRect)
that does the work of renderImage()
(minus the call to draw()
). (You can either have draw(_ rect: CGRect)
call renderImage()
or you can simply rename renderImage()
to draw(_ rect: CGRect)
.)
Depending on your exact needs, you could also set enableSetNeedsDisplay
to true and change the image
didSet
to call setNeedsDisplay()
instead of draw()
. That will have a bit more latency but will avoid attempts to draw too often.