diff options
author | der richter <der.richter@gmx.de> | 2019-03-30 21:26:31 +0100 |
---|---|---|
committer | Jan Ekström <jeebjp@gmail.com> | 2019-04-25 23:02:19 +0300 |
commit | 71ad1e2f4c2b87e677d01c639dbd3d28c118ac55 (patch) | |
tree | bf564e6374790a96f025ea0c44fc57ac7f9f6f5f /video/out/cocoa-cb/video_layer.swift | |
parent | edbc1999145b5593098f09042947bf1b79323d2e (diff) | |
download | mpv-71ad1e2f4c2b87e677d01c639dbd3d28c118ac55.tar.bz2 mpv-71ad1e2f4c2b87e677d01c639dbd3d28c118ac55.tar.xz |
cocoa-cb: remove all force unwrappings of optionals
the force unwrapping of optionals caused many unpredictable segfaults
instead of gracefully exiting or falling back. besides that, it is bad
practice and the code is a lot more stable now.
Diffstat (limited to 'video/out/cocoa-cb/video_layer.swift')
-rw-r--r-- | video/out/cocoa-cb/video_layer.swift | 207 |
1 files changed, 113 insertions, 94 deletions
diff --git a/video/out/cocoa-cb/video_layer.swift b/video/out/cocoa-cb/video_layer.swift index 5de57b9e00..895d9faf29 100644 --- a/video/out/cocoa-cb/video_layer.swift +++ b/video/out/cocoa-cb/video_layer.swift @@ -19,63 +19,61 @@ import Cocoa import OpenGL.GL import OpenGL.GL3 +let glVersions: [CGLOpenGLProfile] = [ + kCGLOGLPVersion_3_2_Core, + kCGLOGLPVersion_Legacy +] + +let glFormatBase: [CGLPixelFormatAttribute] = [ + kCGLPFAOpenGLProfile, + kCGLPFAAccelerated, + kCGLPFADoubleBuffer +] + +let glFormatSoftwareBase: [CGLPixelFormatAttribute] = [ + kCGLPFAOpenGLProfile, + kCGLPFARendererID, + CGLPixelFormatAttribute(UInt32(kCGLRendererGenericFloatID)), + kCGLPFADoubleBuffer +] + +let glFormatOptional: [CGLPixelFormatAttribute] = [ + kCGLPFABackingStore, + kCGLPFAAllowOfflineRenderers, + kCGLPFASupportsAutomaticGraphicsSwitching +] + +let attributeLookUp: [UInt32:String] = [ + kCGLOGLPVersion_3_2_Core.rawValue: "kCGLOGLPVersion_3_2_Core", + kCGLOGLPVersion_Legacy.rawValue: "kCGLOGLPVersion_Legacy", + kCGLPFAOpenGLProfile.rawValue: "kCGLPFAOpenGLProfile", + UInt32(kCGLRendererGenericFloatID): "kCGLRendererGenericFloatID", + kCGLPFARendererID.rawValue: "kCGLPFARendererID", + kCGLPFAAccelerated.rawValue: "kCGLPFAAccelerated", + kCGLPFADoubleBuffer.rawValue: "kCGLPFADoubleBuffer", + kCGLPFABackingStore.rawValue: "kCGLPFABackingStore", + kCGLPFAAllowOfflineRenderers.rawValue: "kCGLPFAAllowOfflineRenderers", + kCGLPFASupportsAutomaticGraphicsSwitching.rawValue: "kCGLPFASupportsAutomaticGraphicsSwitching", +] + class VideoLayer: CAOpenGLLayer { weak var cocoaCB: CocoaCB! - var mpv: MPVHelper! { - get { return cocoaCB == nil ? nil : cocoaCB.mpv } - } + var mpv: MPVHelper { get { return cocoaCB.mpv } } let videoLock = NSLock() let displayLock = NSLock() + let cglContext: CGLContextObj + let cglPixelFormat: CGLPixelFormatObj var needsFlip: Bool = false var forceDraw: Bool = false - var cglContext: CGLContextObj? = nil - var cglPixelFormat: CGLPixelFormatObj? = nil - var surfaceSize: NSSize? + var surfaceSize: NSSize = NSSize(width: 0, height: 0) enum Draw: Int { case normal = 1, atomic, atomicEnd } var draw: Draw = .normal let queue: DispatchQueue = DispatchQueue(label: "io.mpv.queue.draw") - let glVersions: [CGLOpenGLProfile] = [ - kCGLOGLPVersion_3_2_Core, - kCGLOGLPVersion_Legacy - ] - - let glFormatBase: [CGLPixelFormatAttribute] = [ - kCGLPFAOpenGLProfile, - kCGLPFAAccelerated, - kCGLPFADoubleBuffer - ] - - let glFormatSoftwareBase: [CGLPixelFormatAttribute] = [ - kCGLPFAOpenGLProfile, - kCGLPFARendererID, - CGLPixelFormatAttribute(UInt32(kCGLRendererGenericFloatID)), - kCGLPFADoubleBuffer - ] - - let glFormatOptional: [CGLPixelFormatAttribute] = [ - kCGLPFABackingStore, - kCGLPFAAllowOfflineRenderers, - kCGLPFASupportsAutomaticGraphicsSwitching - ] - - let attributeLookUp: [UInt32:String] = [ - kCGLOGLPVersion_3_2_Core.rawValue: "kCGLOGLPVersion_3_2_Core", - kCGLOGLPVersion_Legacy.rawValue: "kCGLOGLPVersion_Legacy", - kCGLPFAOpenGLProfile.rawValue: "kCGLPFAOpenGLProfile", - UInt32(kCGLRendererGenericFloatID): "kCGLRendererGenericFloatID", - kCGLPFARendererID.rawValue: "kCGLPFARendererID", - kCGLPFAAccelerated.rawValue: "kCGLPFAAccelerated", - kCGLPFADoubleBuffer.rawValue: "kCGLPFADoubleBuffer", - kCGLPFABackingStore.rawValue: "kCGLPFABackingStore", - kCGLPFAAllowOfflineRenderers.rawValue: "kCGLPFAAllowOfflineRenderers", - kCGLPFASupportsAutomaticGraphicsSwitching.rawValue: "kCGLPFASupportsAutomaticGraphicsSwitching", - ] - var needsICCUpdate: Bool = false { didSet { if needsICCUpdate == true { @@ -95,24 +93,30 @@ class VideoLayer: CAOpenGLLayer { init(cocoaCB ccb: CocoaCB) { cocoaCB = ccb + cglPixelFormat = VideoLayer.createPixelFormat(ccb.mpv) + cglContext = VideoLayer.createContext(ccb.mpv, cglPixelFormat) super.init() autoresizingMask = [.layerWidthSizable, .layerHeightSizable] backgroundColor = NSColor.black.cgColor - cglPixelFormat = copyCGLPixelFormat(forDisplayMask: 0) - CGLCreateContext(cglPixelFormat!, nil, &cglContext) var i: GLint = 1 - CGLSetParameter(cglContext!, kCGLCPSwapInterval, &i) - CGLSetCurrentContext(cglContext!) + CGLSetParameter(cglContext, kCGLCPSwapInterval, &i) + CGLSetCurrentContext(cglContext) mpv.initRender() mpv.setRenderUpdateCallback(updateCallback, context: self) mpv.setRenderControlCallback(cocoaCB.controlCallback, context: cocoaCB) } + //necessary for when the layer containing window changes the screen override init(layer: Any) { - let oldLayer = layer as! VideoLayer + guard let oldLayer = layer as? VideoLayer else { + fatalError("init(layer: Any) passed an invalid layer") + } cocoaCB = oldLayer.cocoaCB + surfaceSize = oldLayer.surfaceSize + cglPixelFormat = oldLayer.cglPixelFormat + cglContext = oldLayer.cglContext super.init() } @@ -127,7 +131,7 @@ class VideoLayer: CAOpenGLLayer { if inLiveResize == false { isAsynchronous = false } - return mpv != nil && cocoaCB.backendState == .initialized && + return cocoaCB.backendState == .initialized && (forceDraw || mpv.isRenderUpdateFrame()) } @@ -147,7 +151,7 @@ class VideoLayer: CAOpenGLLayer { } updateSurfaceSize() - mpv.drawRender(surfaceSize!, ctx) + mpv.drawRender(surfaceSize, ctx) if needsICCUpdate { needsICCUpdate = false @@ -158,12 +162,12 @@ class VideoLayer: CAOpenGLLayer { func updateSurfaceSize() { var dims: [GLint] = [0, 0, 0, 0] glGetIntegerv(GLenum(GL_VIEWPORT), &dims) - surfaceSize = NSMakeSize(CGFloat(dims[2]), CGFloat(dims[3])) + surfaceSize = NSSize(width: CGFloat(dims[2]), height: CGFloat(dims[3])) - if NSEqualSizes(surfaceSize!, NSZeroSize) { + if NSEqualSizes(surfaceSize, NSZeroSize) { surfaceSize = bounds.size - surfaceSize!.width *= contentsScale - surfaceSize!.height *= contentsScale + surfaceSize.width *= contentsScale + surfaceSize.height *= contentsScale } } @@ -182,28 +186,65 @@ class VideoLayer: CAOpenGLLayer { } override func copyCGLPixelFormat(forDisplayMask mask: UInt32) -> CGLPixelFormatObj { - if cglPixelFormat != nil { return cglPixelFormat! } + return cglPixelFormat + } + + override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj { + contentsScale = cocoaCB.window?.backingScaleFactor ?? 1.0 + return cglContext + } + + let updateCallback: mpv_render_update_fn = { (ctx) in + let layer: VideoLayer = unsafeBitCast(ctx, to: VideoLayer.self) + layer.update() + } + + override func display() { + displayLock.lock() + let isUpdate = needsFlip + super.display() + CATransaction.flush() + if isUpdate && needsFlip { + CGLSetCurrentContext(cglContext) + if mpv.isRenderUpdateFrame() { + mpv.drawRender(NSZeroSize, cglContext, skip: true) + } + } + displayLock.unlock() + } + + func update(force: Bool = false) { + if force { forceDraw = true } + queue.async { + if self.forceDraw || !self.inLiveResize { + self.needsFlip = true + self.display() + } + } + } + class func createPixelFormat(_ mpv: MPVHelper) -> CGLPixelFormatObj { var pix: CGLPixelFormatObj? var err: CGLError = CGLError(rawValue: 0) + let swRender = mpv.macOpts?.cocoa_cb_sw_renderer ?? -1 - if mpv.macOpts!.cocoa_cb_sw_renderer != 1 { - (pix, err) = createPixelFormat() + if swRender != 1 { + (pix, err) = VideoLayer.findPixelFormat(mpv) } - if (err != kCGLNoError || pix == nil) && mpv.macOpts!.cocoa_cb_sw_renderer != 0 { - (pix, err) = createPixelFormat(software: true) + if (err != kCGLNoError || pix == nil) && swRender != 0 { + (pix, err) = VideoLayer.findPixelFormat(mpv, software: true) } - if err != kCGLNoError || pix == nil { + guard let pixelFormat = pix, err == kCGLNoError else { mpv.sendError("Couldn't create any CGL pixel format") exit(1) } - return pix! + return pixelFormat } - func createPixelFormat(software: Bool = false) -> (CGLPixelFormatObj?, CGLError) { + class func findPixelFormat(_ mpv: MPVHelper, software: Bool = false) -> (CGLPixelFormatObj?, CGLError) { var pix: CGLPixelFormatObj? var err: CGLError = CGLError(rawValue: 0) var npix: GLint = 0 @@ -221,7 +262,7 @@ class VideoLayer: CAOpenGLLayer { glFormat.remove(at: index) } else { let attArray = glFormat.map({ (value: _CGLPixelFormatAttribute) -> String in - return attributeLookUp[value.rawValue]! + return attributeLookUp[value.rawValue] ?? "unknown attribute" }) mpv.sendVerbose("Created CGL pixel format with attributes: " + @@ -236,45 +277,23 @@ class VideoLayer: CAOpenGLLayer { "\(software ? "software" : "hardware accelerated") " + "CGL pixel format: \(errS) (\(err.rawValue))") - if software == false && mpv.macOpts!.cocoa_cb_sw_renderer == -1 { + if software == false && (mpv.macOpts?.cocoa_cb_sw_renderer ?? -1) == -1 { mpv.sendWarning("Falling back to software renderer") } return (pix, err) } - override func copyCGLContext(forPixelFormat pf: CGLPixelFormatObj) -> CGLContextObj { - contentsScale = cocoaCB.window.backingScaleFactor - return cglContext! - } + class func createContext(_ mpv: MPVHelper, _ pixelFormat: CGLPixelFormatObj) -> CGLContextObj { + var context: CGLContextObj? + let error = CGLCreateContext(pixelFormat, nil, &context) - let updateCallback: mpv_render_update_fn = { (ctx) in - let layer: VideoLayer = MPVHelper.bridge(ptr: ctx!) - layer.update() - } - - override func display() { - displayLock.lock() - let isUpdate = needsFlip - super.display() - CATransaction.flush() - if isUpdate && needsFlip { - CGLSetCurrentContext(cglContext!) - if mpv.isRenderUpdateFrame() { - mpv.drawRender(NSZeroSize, cglContext!, skip: true) - } + guard let cglContext = context, error == kCGLNoError else { + let errS = String(cString: CGLErrorString(error)) + mpv.sendError("Couldn't create a CGLContext: " + errS) + exit(1) } - displayLock.unlock() - } - func update(force: Bool = false) { - if force { forceDraw = true } - queue.async { - if self.forceDraw || !self.inLiveResize { - self.needsFlip = true - self.display() - } - } + return cglContext } - } |