From 965ba23303d980c239e2b0191488766cfa7b0f75 Mon Sep 17 00:00:00 2001 From: Akemi Date: Wed, 21 Mar 2018 21:09:05 +0100 Subject: cocoa-cb: render on a dedicated dispatch queue we rendered on the displaylink thread which wasn't the best idea. if rendering took too long or was blocking it also blocked the displaylink callback. when that happened new vsyncs were reported delayed or not at all. consequently the mpv_render_context_report_swap function wasn't called consistently and that could cause bad video playback. so the rendering is moved to a dedicated dispatch queue. furthermore the update callback starts a layer update directly instead of the displaylink callback, making the rendering a bit more consistent. --- video/out/cocoa-cb/video_layer.swift | 51 ++++++++++++++++++++---------------- video/out/cocoa-cb/window.swift | 6 ++--- video/out/cocoa_cb_common.swift | 7 ++--- 3 files changed, 36 insertions(+), 28 deletions(-) diff --git a/video/out/cocoa-cb/video_layer.swift b/video/out/cocoa-cb/video_layer.swift index 51d14f84a3..2e347ba22e 100644 --- a/video/out/cocoa-cb/video_layer.swift +++ b/video/out/cocoa-cb/video_layer.swift @@ -27,21 +27,22 @@ class VideoLayer: CAOpenGLLayer { } let videoLock = NSLock() + let displayLock = NSLock() var hasVideo: Bool = false - var neededFlips: Int = 0 + var needsFlip: Bool = false + var canDrawOffScreen: Bool = false var cglContext: CGLContextObj? = nil var surfaceSize: NSSize? enum Draw: Int { case normal = 1, atomic, atomicEnd } var draw: Draw = .normal - var canDrawOffScreen: Bool = false - var lastThread: Thread? = nil + let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue.draw") var needsICCUpdate: Bool = false { didSet { if needsICCUpdate == true { - neededFlips += 1 + update() } } } @@ -51,6 +52,7 @@ class VideoLayer: CAOpenGLLayer { if inLiveResize { isAsynchronous = true } + update() } } @@ -92,9 +94,8 @@ class VideoLayer: CAOpenGLLayer { pixelFormat pf: CGLPixelFormatObj, forLayerTime t: CFTimeInterval, displayTime ts: UnsafePointer?) { - neededFlips = 0 - canDrawOffScreen = Thread.current == lastThread - lastThread = Thread.current + needsFlip = false + canDrawOffScreen = true draw(ctx) } @@ -197,36 +198,42 @@ class VideoLayer: CAOpenGLLayer { let updateCallback: mpv_render_update_fn = { (ctx) in let layer: VideoLayer = MPVHelper.bridge(ptr: ctx!) - layer.neededFlips += 1 + layer.update() } override func display() { + displayLock.lock() + let isUpdate = needsFlip super.display() CATransaction.flush() + if isUpdate { + if !cocoaCB.window.occlusionState.contains(.visible) && + needsFlip && canDrawOffScreen + { + CGLSetCurrentContext(cglContext!) + draw(cglContext!) + } else if needsFlip { + update() + } + } + displayLock.unlock() } func setVideo(_ state: Bool) { videoLock.lock() hasVideo = state - neededFlips = 0 videoLock.unlock() } - func reportFlip() { - mpv.reportRenderFlip() - videoLock.lock() - if !isAsynchronous && neededFlips > 0 && hasVideo { - if !cocoaCB.window.occlusionState.contains(.visible) && - neededFlips > 1 && canDrawOffScreen - { - CGLSetCurrentContext(cglContext!) - draw(cglContext!) - display() - } else { - display() + func update() { + queue.async { + self.videoLock.lock() + if !self.inLiveResize && self.hasVideo { + self.needsFlip = true + self.display() } + self.videoLock.unlock() } - videoLock.unlock() } } diff --git a/video/out/cocoa-cb/window.swift b/video/out/cocoa-cb/window.swift index b296eb25c8..b3db7aeb8f 100644 --- a/video/out/cocoa-cb/window.swift +++ b/video/out/cocoa-cb/window.swift @@ -305,7 +305,7 @@ class Window: NSWindow, NSWindowDelegate { } isAnimating = false - cocoaCB.layer.neededFlips += 1 + cocoaCB.layer.update() cocoaCB.checkShutdown() } @@ -316,7 +316,7 @@ class Window: NSWindow, NSWindowDelegate { endAnimation() isInFullscreen = true cocoaCB.flagEvents(VO_EVENT_FULLSCREEN_STATE) - cocoaCB.layer.neededFlips += 1 + cocoaCB.layer.update() } func setToWindow() { @@ -327,7 +327,7 @@ class Window: NSWindow, NSWindowDelegate { endAnimation() isInFullscreen = false cocoaCB.flagEvents(VO_EVENT_FULLSCREEN_STATE) - cocoaCB.layer.neededFlips += 1 + cocoaCB.layer.update() } func getFsAnimationDuration(_ def: Double) -> Double{ diff --git a/video/out/cocoa_cb_common.swift b/video/out/cocoa_cb_common.swift index e8d8bb44f4..659f9f84ce 100644 --- a/video/out/cocoa_cb_common.swift +++ b/video/out/cocoa_cb_common.swift @@ -86,7 +86,7 @@ class CocoaCB: NSObject { } else { layer.setVideo(true) updateWindowSize() - layer.neededFlips += 1 + layer.update() } } @@ -150,7 +150,7 @@ class CocoaCB: NSObject { flagsOut: UnsafeMutablePointer, displayLinkContext: UnsafeMutableRawPointer?) -> CVReturn in let ccb: CocoaCB = MPVHelper.bridge(ptr: displayLinkContext!) - ccb.layer.reportFlip() + ccb.mpv.reportRenderFlip() return kCVReturnSuccess } @@ -160,7 +160,7 @@ class CocoaCB: NSObject { CVDisplayLinkSetCurrentCGDisplay(link!, displayId) if #available(macOS 10.12, *) { CVDisplayLinkSetOutputHandler(link!) { link, now, out, inFlags, outFlags -> CVReturn in - self.layer.reportFlip() + self.mpv.reportRenderFlip() return kCVReturnSuccess } } else { @@ -454,6 +454,7 @@ class CocoaCB: NSObject { func shutdown(_ destroy: Bool = false) { setCursorVisiblility(true) + layer.setVideo(false) stopDisplaylink() uninitLightSensor() removeDisplayReconfigureObserver() -- cgit v1.2.3