mirror of https://github.com/mpv-player/mpv
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:
parent
9975835bde
commit
965ba23303
|
@ -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()
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue