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:
parent
317d3ac266
commit
9e466ee621
@ -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, ¶ms);
|
mpv_render_context_render(mpvRenderContext, ¶ms);
|
||||||
@ -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) {
|
||||||
|
@ -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()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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()
|
||||||
|
Loading…
Reference in New Issue
Block a user