I'm trying to receive frame data and render to MTKView in 60fps.
My MTKView almost the same as PreviewView.swift in Reference about SwiftUI using MTKView
ContentView:
struct ContentView: View {
@State var navigationPath = NavigationPath()
@StateObject var ndi_c = NDI.shared
init(){
UIApplication.shared.isIdleTimerDisabled = true
}
var body: some View {
NavigationStack (path: $navigationPath){
#if !(targetEnvironment(simulator))
ZStack{
//This is the MTKView, and code is almost same in https://github.com/frankschlegel/core-image-by-example/blob/main/Shared/PreviewView.swift
NDIView(imagePublisher: self.ndi_c.$NDI_Frame.eraseToAnyPublisher())
.onAppear(){
ndi_c.StartRecv()
ARData.shared.HideARView = NDIView_Top
}
//Doing something...
}.navigationDestination(for: viewDest.self) { target in
switch target {
case .MainView:
ContentView()
case .SettingsView:
Settings()
}
}
}
#endif
}
}
}
This is code about ndi_c.StartRecv()
:
class NDI: ObservableObject{
@Published var NDI_Frame: CIImage?
let NDI_Queue = DispatchQueue(label: "NDI_recv")
static var shared = NDI()
var ndi_t: NDIWrapper?
var Connected: Bool = false
init(){
ndi_t = NDIWrapper()
}
\\Do Something...
func PrepareFrame() -> CVPixelBuffer?{
var Buf: CVPixelBuffer?
if let data = self.ndi_t?.getRecvBuf(){
Buf = data.takeRetainedValue()
}
return Buf
}
func StartRecv(){
Connected = ndi_t!.startRecv(SelectedSource ?? "")
NDI_Queue.async {
while(self.Connected){
if let buf = self.PrepareFrame(){
let ciImage = CIImage(cvPixelBuffer: buf)
DispatchQueue.main.async {
self.NDI_Frame = ciImage
}
}
}
}
}
}
I use PrepareFrame()
to grab and create CVPixelBuffer
from uint8_t*
, After that, I convert it to CIImage
.
Finally I use @Published
to update NDI_Frame
and refresh to MTKView
on main thread.
Unfortunately the view is laggy, Framerate is very unstable.
Creating CVPixelBuffer in my code only cost about 5% CPU usage .
But Main thread is overloading when I publish the data.
Sorry, I'm very new on Swift.
Please tell me where am I doing wrong.
Appreciate it.
CodePudding user response:
Don't you think there is an infinite loop going on in the code above: while(self.Connected)
?
I would recommend using a timer or some other form of scheduling to limit the amount of times the loop is run or rethink the code totally.
CodePudding user response:
SwiftUI view data state updates aren't designed to run at 60fps, maybe 1 per second max, so I think you should implement your custom rendering at a lower level in the system.