Home > Software design >  Why CPU usage is high when I using @Published?
Why CPU usage is high when I using @Published?

Time:12-06

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.

  • Related