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.
This commit is contained in:
Akemi 2018-03-21 21:09:05 +01:00 committed by Kevin Mitchell
parent 9975835bde
commit 965ba23303
3 changed files with 36 additions and 28 deletions

View File

@ -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<CVTimeStamp>?) {
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()
}
}

View File

@ -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{

View File

@ -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<CVOptionFlags>,
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()