1
mirror of https://github.com/mpv-player/mpv synced 2024-10-30 04:46:41 +01:00

cocoa-cb: use libmpv's advanced rendering control and timing

this adds support for GPU rendered screenshots, DR (theoretically) and
possible other advanced functions in the future that need to be executed
from the rendering thread.
additionally frames that would be off screen or not be displayed when on
screen are being dropped now.
This commit is contained in:
Akemi 2018-06-12 02:48:31 +02:00 committed by Jan Ekström
parent 317d3ac266
commit 9e466ee621
4 changed files with 41 additions and 33 deletions

View File

@ -36,6 +36,7 @@ class MPVHelper: NSObject {
var mpctx: UnsafeMutablePointer<MPContext>? var mpctx: UnsafeMutablePointer<MPContext>?
var macOpts: macos_opts? var macOpts: macos_opts?
var fbo: GLint = 1 var fbo: GLint = 1
let deinitLock = NSLock()
init(_ mpv: OpaquePointer) { init(_ mpv: OpaquePointer) {
super.init() super.init()
@ -58,6 +59,7 @@ class MPVHelper: NSObject {
} }
func initRender() { func initRender() {
var advanced: CInt = 1
let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String) let api = UnsafeMutableRawPointer(mutating: (MPV_RENDER_API_TYPE_OPENGL as NSString).utf8String)
var pAddress = mpv_opengl_init_params(get_proc_address: getProcAddress, var pAddress = mpv_opengl_init_params(get_proc_address: getProcAddress,
get_proc_address_ctx: nil, get_proc_address_ctx: nil,
@ -65,6 +67,7 @@ class MPVHelper: NSObject {
var params: [mpv_render_param] = [ var params: [mpv_render_param] = [
mpv_render_param(type: MPV_RENDER_PARAM_API_TYPE, data: api), mpv_render_param(type: MPV_RENDER_PARAM_API_TYPE, data: api),
mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, data: &pAddress), mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_INIT_PARAMS, data: &pAddress),
mpv_render_param(type: MPV_RENDER_PARAM_ADVANCED_CONTROL, data: &advanced),
mpv_render_param() mpv_render_param()
] ]
@ -110,13 +113,26 @@ class MPVHelper: NSObject {
func reportRenderFlip() { func reportRenderFlip() {
if mpvRenderContext == nil { return } if mpvRenderContext == nil { return }
mpv_render_context_report_swap(mpvRenderContext) mpv_render_context_report_swap(mpvRenderContext)
} }
func drawRender(_ surface: NSSize) { func isRenderUpdateFrame() -> Bool {
deinitLock.lock()
if mpvRenderContext == nil {
deinitLock.unlock()
return false
}
let flags: UInt64 = mpv_render_context_update(mpvRenderContext)
deinitLock.unlock()
return flags & UInt64(MPV_RENDER_UPDATE_FRAME.rawValue) > 0
}
func drawRender(_ surface: NSSize, skip: Bool = false) {
deinitLock.lock()
if mpvRenderContext != nil { if mpvRenderContext != nil {
var i: GLint = 0 var i: GLint = 0
var flip: CInt = 1 var flip: CInt = 1
var skip: CInt = skip ? 1 : 0
glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i) glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i)
// CAOpenGLLayer has ownership of FBO zero yet can return it to us, // CAOpenGLLayer has ownership of FBO zero yet can return it to us,
// so only utilize a newly received FBO ID if it is nonzero. // so only utilize a newly received FBO ID if it is nonzero.
@ -129,6 +145,7 @@ class MPVHelper: NSObject {
var params: [mpv_render_param] = [ var params: [mpv_render_param] = [
mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: &data), mpv_render_param(type: MPV_RENDER_PARAM_OPENGL_FBO, data: &data),
mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: &flip), mpv_render_param(type: MPV_RENDER_PARAM_FLIP_Y, data: &flip),
mpv_render_param(type: MPV_RENDER_PARAM_SKIP_RENDERING, data: &skip),
mpv_render_param() mpv_render_param()
] ]
mpv_render_context_render(mpvRenderContext, &params); mpv_render_context_render(mpvRenderContext, &params);
@ -136,6 +153,7 @@ class MPVHelper: NSObject {
glClearColor(0, 0, 0, 1) glClearColor(0, 0, 0, 1)
glClear(GLbitfield(GL_COLOR_BUFFER_BIT)) glClear(GLbitfield(GL_COLOR_BUFFER_BIT))
} }
deinitLock.unlock()
} }
func setRenderICCProfile(_ profile: NSColorSpace) { func setRenderICCProfile(_ profile: NSColorSpace) {
@ -258,8 +276,10 @@ class MPVHelper: NSObject {
func deinitRender() { func deinitRender() {
mpv_render_context_set_update_callback(mpvRenderContext, nil, nil) mpv_render_context_set_update_callback(mpvRenderContext, nil, nil)
mp_render_context_set_control_callback(mpvRenderContext, nil, nil) mp_render_context_set_control_callback(mpvRenderContext, nil, nil)
deinitLock.lock()
mpv_render_context_free(mpvRenderContext) mpv_render_context_free(mpvRenderContext)
mpvRenderContext = nil mpvRenderContext = nil
deinitLock.unlock()
} }
func deinitMPV(_ destroy: Bool = false) { func deinitMPV(_ destroy: Bool = false) {

View File

@ -28,9 +28,8 @@ class VideoLayer: CAOpenGLLayer {
let videoLock = NSLock() let videoLock = NSLock()
let displayLock = NSLock() let displayLock = NSLock()
var hasVideo: Bool = false
var needsFlip: Bool = false var needsFlip: Bool = false
var canDrawOffScreen: Bool = false var forceDraw: Bool = false
var cglContext: CGLContextObj? = nil var cglContext: CGLContextObj? = nil
var cglPixelFormat: CGLPixelFormatObj? = nil var cglPixelFormat: CGLPixelFormatObj? = nil
var surfaceSize: NSSize? var surfaceSize: NSSize?
@ -53,7 +52,7 @@ class VideoLayer: CAOpenGLLayer {
if inLiveResize { if inLiveResize {
isAsynchronous = true isAsynchronous = true
} }
update() update(force: true)
} }
} }
@ -91,7 +90,8 @@ class VideoLayer: CAOpenGLLayer {
if inLiveResize == false { if inLiveResize == false {
isAsynchronous = false isAsynchronous = false
} }
return mpv != nil && cocoaCB.backendState == .initialized return mpv != nil && cocoaCB.backendState == .initialized &&
(forceDraw || mpv.isRenderUpdateFrame())
} }
override func draw(inCGLContext ctx: CGLContextObj, override func draw(inCGLContext ctx: CGLContextObj,
@ -99,11 +99,8 @@ class VideoLayer: CAOpenGLLayer {
forLayerTime t: CFTimeInterval, forLayerTime t: CFTimeInterval,
displayTime ts: UnsafePointer<CVTimeStamp>?) { displayTime ts: UnsafePointer<CVTimeStamp>?) {
needsFlip = false needsFlip = false
canDrawOffScreen = true forceDraw = false
draw(ctx)
}
func draw(_ ctx: CGLContextObj) {
if draw.rawValue >= Draw.atomic.rawValue { if draw.rawValue >= Draw.atomic.rawValue {
if draw == .atomic { if draw == .atomic {
draw = .atomicEnd draw = .atomicEnd
@ -135,7 +132,7 @@ class VideoLayer: CAOpenGLLayer {
} }
func atomicDrawingStart() { func atomicDrawingStart() {
if draw == .normal && hasVideo { if draw == .normal {
NSDisableScreenUpdates() NSDisableScreenUpdates()
draw = .atomic draw = .atomic
} }
@ -225,33 +222,22 @@ class VideoLayer: CAOpenGLLayer {
let isUpdate = needsFlip let isUpdate = needsFlip
super.display() super.display()
CATransaction.flush() CATransaction.flush()
if isUpdate { if isUpdate && needsFlip {
if !cocoaCB.window.occlusionState.contains(.visible) && CGLSetCurrentContext(cglContext!)
needsFlip && canDrawOffScreen if mpv.isRenderUpdateFrame() {
{ mpv.drawRender(NSZeroSize, skip: true)
CGLSetCurrentContext(cglContext!)
draw(cglContext!)
} else if needsFlip {
update()
} }
} }
displayLock.unlock() displayLock.unlock()
} }
func setVideo(_ state: Bool) { func update(force: Bool = false) {
videoLock.lock() if force { forceDraw = true }
hasVideo = state
videoLock.unlock()
}
func update() {
queue.async { queue.async {
self.videoLock.lock() if self.forceDraw || !self.inLiveResize {
if !self.inLiveResize && self.hasVideo {
self.needsFlip = true self.needsFlip = true
self.display() self.display()
} }
self.videoLock.unlock()
} }
} }

View File

@ -613,6 +613,12 @@ class Window: NSWindow, NSWindowDelegate {
cocoaCB.updateCusorVisibility() cocoaCB.updateCusorVisibility()
} }
func windowDidChangeOcclusionState(_ notification: Notification) {
if occlusionState.contains(.visible) {
cocoaCB.layer.update(force: true)
}
}
func windowWillMove(_ notification: Notification) { func windowWillMove(_ notification: Notification) {
isMoving = true isMoving = true
} }

View File

@ -72,7 +72,6 @@ class CocoaCB: NSObject {
} }
func uninit() { func uninit() {
layer.setVideo(false)
window.orderOut(nil) window.orderOut(nil)
} }
@ -81,7 +80,6 @@ class CocoaCB: NSObject {
DispatchQueue.main.sync { self.initBackend(vo) } DispatchQueue.main.sync { self.initBackend(vo) }
} else { } else {
DispatchQueue.main.async { DispatchQueue.main.async {
self.layer.setVideo(true)
self.updateWindowSize(vo) self.updateWindowSize(vo)
self.layer.update() self.layer.update()
} }
@ -106,7 +104,6 @@ class CocoaCB: NSObject {
window.makeMain() window.makeMain()
window.makeKeyAndOrderFront(nil) window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true) NSApp.activate(ignoringOtherApps: true)
layer.setVideo(true)
if Bool(opts.fullscreen) { if Bool(opts.fullscreen) {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -449,7 +446,6 @@ class CocoaCB: NSObject {
func shutdown(_ destroy: Bool = false) { func shutdown(_ destroy: Bool = false) {
setCursorVisiblility(true) setCursorVisiblility(true)
layer.setVideo(false)
stopDisplaylink() stopDisplaylink()
uninitLightSensor() uninitLightSensor()
removeDisplayReconfigureObserver() removeDisplayReconfigureObserver()