mirror of
https://github.com/yattee/yattee.git
synced 2025-11-16 06:58:43 +00:00
Refactored glUpdate to use requestRedraw method for better control. Added needsRedraw flag to prevent redundant display calls. Enabled asynchronous drawing on VideoLayer for improved performance. Modified displayLinkCallback to only report swap without triggering display to avoid flooding the main thread.
140 lines
4.4 KiB
Swift
140 lines
4.4 KiB
Swift
import Cocoa
|
|
import Libmpv
|
|
import OpenGL.GL
|
|
import OpenGL.GL3
|
|
|
|
final class VideoLayer: CAOpenGLLayer {
|
|
var client: MPVClient!
|
|
private var needsRedraw = false
|
|
private let redrawQueue = DispatchQueue(label: "com.yattee.videolayer.redraw", qos: .userInteractive)
|
|
|
|
override init() {
|
|
super.init()
|
|
autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
|
|
backgroundColor = NSColor.black.cgColor
|
|
// Enable asynchronous drawing for better performance
|
|
isAsynchronous = true
|
|
}
|
|
|
|
@available(*, unavailable)
|
|
required init?(coder _: NSCoder) {
|
|
fatalError("init(coder:) has not been implemented")
|
|
}
|
|
|
|
override func canDraw(
|
|
inCGLContext _: CGLContextObj,
|
|
pixelFormat _: CGLPixelFormatObj,
|
|
forLayerTime _: CFTimeInterval,
|
|
displayTime _: UnsafePointer<CVTimeStamp>?
|
|
) -> Bool {
|
|
true
|
|
}
|
|
|
|
override func draw(
|
|
inCGLContext ctx: CGLContextObj,
|
|
pixelFormat _: CGLPixelFormatObj,
|
|
forLayerTime _: CFTimeInterval,
|
|
displayTime _: UnsafePointer<CVTimeStamp>?
|
|
) {
|
|
needsRedraw = false
|
|
|
|
var i: GLint = 0
|
|
var flip: CInt = 1
|
|
var ditherDepth = 8
|
|
glGetIntegerv(GLenum(GL_DRAW_FRAMEBUFFER_BINDING), &i)
|
|
|
|
if client.mpvGL != nil {
|
|
var data = mpv_opengl_fbo(
|
|
fbo: Int32(i),
|
|
w: Int32(bounds.size.width),
|
|
h: Int32(bounds.size.height),
|
|
internal_format: 0
|
|
)
|
|
var params: [mpv_render_param] = [
|
|
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_DEPTH, data: &ditherDepth),
|
|
mpv_render_param()
|
|
]
|
|
mpv_render_context_render(client.mpvGL, ¶ms)
|
|
} else {
|
|
glClearColor(0, 0, 0, 1)
|
|
glClear(GLbitfield(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT))
|
|
}
|
|
|
|
CGLFlushDrawable(ctx)
|
|
}
|
|
|
|
override func copyCGLPixelFormat(forDisplayMask _: UInt32) -> CGLPixelFormatObj {
|
|
let attrs: [CGLPixelFormatAttribute] = [
|
|
kCGLPFAOpenGLProfile, CGLPixelFormatAttribute(kCGLOGLPVersion_3_2_Core.rawValue),
|
|
kCGLPFADoubleBuffer,
|
|
kCGLPFAAllowOfflineRenderers,
|
|
kCGLPFABackingStore,
|
|
kCGLPFAAccelerated,
|
|
kCGLPFASupportsAutomaticGraphicsSwitching,
|
|
_CGLPixelFormatAttribute(rawValue: 0)
|
|
]
|
|
|
|
var npix: GLint = 0
|
|
var pix: CGLPixelFormatObj?
|
|
CGLChoosePixelFormat(attrs, &pix, &npix)
|
|
|
|
return pix!
|
|
}
|
|
|
|
override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj {
|
|
let ctx = super.copyCGLContext(forPixelFormat: pf)
|
|
|
|
var i: GLint = 1
|
|
CGLSetParameter(ctx, kCGLCPSwapInterval, &i)
|
|
CGLEnable(ctx, kCGLCEMPEngine)
|
|
CGLSetCurrentContext(ctx)
|
|
|
|
client.create()
|
|
initDisplayLink()
|
|
|
|
return ctx
|
|
}
|
|
|
|
override func display() {
|
|
// Mark as needing display without blocking
|
|
guard !needsRedraw else { return }
|
|
needsRedraw = true
|
|
super.display()
|
|
}
|
|
|
|
func requestRedraw() {
|
|
// Called from MPV's glUpdate callback - use setNeedsDisplay for efficient batching
|
|
DispatchQueue.main.async { [weak self] in
|
|
self?.setNeedsDisplay()
|
|
}
|
|
}
|
|
|
|
let displayLinkCallback: CVDisplayLinkOutputCallback = { _, _, _, _, _, displayLinkContext -> CVReturn in
|
|
let layer: VideoLayer = unsafeBitCast(displayLinkContext, to: VideoLayer.self)
|
|
if layer.client?.mpvGL != nil {
|
|
// Just report swap - don't trigger display here to avoid flooding main thread
|
|
mpv_render_context_report_swap(layer.client.mpvGL)
|
|
}
|
|
return kCVReturnSuccess
|
|
}
|
|
|
|
func initDisplayLink() {
|
|
let displayId = UInt32(NSScreen.main?.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")] as! Int)
|
|
|
|
CVDisplayLinkCreateWithCGDisplay(displayId, &client.link)
|
|
CVDisplayLinkSetOutputCallback(
|
|
client.link!, displayLinkCallback,
|
|
UnsafeMutableRawPointer(Unmanaged.passUnretained(client.layer).toOpaque())
|
|
)
|
|
CVDisplayLinkStart(client.link!)
|
|
}
|
|
|
|
func uninitDisplaylink() {
|
|
if CVDisplayLinkIsRunning(client.link!) {
|
|
CVDisplayLinkStop(client.link!)
|
|
}
|
|
}
|
|
}
|