Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mac: add macosvk gpu context #12493

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DOCS/man/options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6312,6 +6312,8 @@ them.
X11/EGL
android
Android/EGL. Requires ``--wid`` be set to an ``android.view.Surface``.
macosvk
macOS/Vulkan/MoltenVK (``--vo=gpu-next`` only).

``--gpu-api=<type>``
Controls which type of graphics APIs will be accepted:
Expand Down
9 changes: 9 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -1287,6 +1287,10 @@ if features['vulkan'] and features['x11']
sources += files('video/out/vulkan/context_xlib.c')
endif

if features['vulkan'] and features['cocoa']
sources += files('video/out/vulkan/context_mac.m')
endif

features += {'vk-khr-display': cc.has_function('vkCreateDisplayPlaneSurfaceKHR', prefix: '#include <vulkan/vulkan_core.h>',
dependencies: [vulkan])}
if features['vk-khr-display']
Expand Down Expand Up @@ -1547,6 +1551,7 @@ if cocoa.found() and swift.allowed()
'osdep/macos/mpv_helper.swift',
'osdep/macos/swift_compat.swift',
'osdep/macos/swift_extensions.swift',
'osdep/macos/precise_timer.swift',
'video/out/mac/common.swift',
'video/out/mac/title_bar.swift',
'video/out/mac/view.swift',
Expand All @@ -1562,6 +1567,10 @@ if features['macos-cocoa-cb']
swift_sources += files('video/out/cocoa_cb_common.swift',
'video/out/mac/gl_layer.swift')
endif
if features['cocoa'] and features['vulkan']
swift_sources += files('video/out/mac_common.swift',
'video/out/mac/metal_layer.swift')
endif

macos_media_player = get_option('macos-media-player').require(
macos_10_12_2_features.allowed() and swift.allowed(),
Expand Down
3 changes: 2 additions & 1 deletion osdep/macOS_swift_bridge.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

// including IOKit here again doesn't make sense, but otherwise the swift
// including frameworks here again doesn't make sense, but otherwise the swift
// compiler doesn't include the needed header in our generated header file
#import <IOKit/pwr_mgt/IOPMLib.h>
#import <QuartzCore/QuartzCore.h>

#include "player/client.h"
#include "video/out/libmpv.h"
Expand Down
139 changes: 139 additions & 0 deletions osdep/macos/precise_timer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

import Cocoa

class PreciseTimer {
unowned var common: Common
var mpv: MPVHelper? { get { return common.mpv } }

let condition = NSCondition()
var events: [[String:Any]] = []
var timebaseRatio: Double = 1.0
var isRunning: Bool = true
var isHighPrecision: Bool = false

var thread: pthread_t?
var threadPort: thread_port_t? = nil
let typeNumber: mach_msg_type_number_t
let policyFlavor = thread_policy_flavor_t(THREAD_TIME_CONSTRAINT_POLICY)
let policyCount = MemoryLayout<thread_time_constraint_policy>.size /
MemoryLayout<integer_t>.size

init(common com: Common) {
common = com
var timebase: mach_timebase_info = mach_timebase_info()
var attr: pthread_attr_t = pthread_attr_t()
var param: sched_param = sched_param()
mach_timebase_info(&timebase)
pthread_attr_init(&attr)

typeNumber = mach_msg_type_number_t(policyCount)
timebaseRatio = (Double(timebase.numer) / Double(timebase.denom)) / CVGetHostClockFrequency()
param.sched_priority = sched_get_priority_max(SCHED_FIFO)
pthread_attr_setschedparam(&attr, &param)
pthread_attr_setschedpolicy(&attr, SCHED_FIFO)
pthread_create(&thread, &attr, entryC, MPVHelper.bridge(obj: self))
threadPort = pthread_mach_thread_np(thread!)
}

func updatePolicy(refreshRate: Double = 60.0) {
let period = UInt32(1.0 / refreshRate / timebaseRatio)
var policy = thread_time_constraint_policy(
period: period,
computation: UInt32(200000),
constraint: period / 10,
preemptible: 1
)

let success = withUnsafeMutablePointer(to: &policy) {
$0.withMemoryRebound(to: integer_t.self, capacity: policyCount) {
thread_policy_set(threadPort!, policyFlavor, $0, typeNumber)
}
}

isHighPrecision = success == KERN_SUCCESS
if !isHighPrecision {
common.log.sendWarning("Couldn't create a high precision timer")
}
}

func terminate() {
condition.lock()
isRunning = false
condition.signal()
condition.unlock()
// TODO ! shit
pthread_kill(thread!, SIGALRM)
pthread_join(thread!, nil)
}

func scheduleAt(time: UInt64, closure: @escaping () -> () ) {
condition.lock()
let firstEventTime = events.first?["time"] as? UInt64 ?? 0
let lastEventTime = events.last?["time"] as? UInt64 ?? 0
events.append(["time": time, "closure": closure])

if lastEventTime > time {
events.sort{ ($0["time"] as! UInt64) < ($1["time"] as! UInt64) }
}

condition.signal()
condition.unlock()

if firstEventTime > time {
pthread_kill(thread!, SIGALRM)
}
}

let threadSignal: @convention(c) (Int32) -> () = { (sig: Int32) in }

let entryC: @convention(c) (UnsafeMutableRawPointer) -> UnsafeMutableRawPointer? = { (ptr: UnsafeMutableRawPointer) in
let ptimer: PreciseTimer = MPVHelper.bridge(ptr: ptr)
ptimer.entry()
return nil
}

func entry() {
signal(SIGALRM, threadSignal)

while isRunning {
condition.lock()
while events.count == 0 && isRunning {
condition.wait()
}

if !isRunning { break }

let event = events.first
condition.unlock()

let time = event?["time"] as! UInt64
let closure = event?["closure"] as! () -> ()

mach_wait_until(time)

condition.lock()
if (events.first?["time"] as! UInt64) == time && isRunning {
closure()
events.removeFirst()
}
condition.unlock()
}
}

}
5 changes: 5 additions & 0 deletions video/out/gpu/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ extern const struct ra_ctx_fns ra_ctx_vulkan_wayland;
extern const struct ra_ctx_fns ra_ctx_vulkan_win;
extern const struct ra_ctx_fns ra_ctx_vulkan_xlib;
extern const struct ra_ctx_fns ra_ctx_vulkan_android;
extern const struct ra_ctx_fns ra_ctx_vulkan_macos;
extern const struct ra_ctx_fns ra_ctx_vulkan_display;

/* Direct3D 11 */
Expand Down Expand Up @@ -110,6 +111,10 @@ static const struct ra_ctx_fns *contexts[] = {
#if HAVE_X11
&ra_ctx_vulkan_xlib,
#endif
// check for molten instead?
#if HAVE_COCOA
&ra_ctx_vulkan_macos,
#endif
#if HAVE_VK_KHR_DISPLAY
&ra_ctx_vulkan_display,
#endif
Expand Down
43 changes: 43 additions & 0 deletions video/out/mac/metal_layer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

import Cocoa

class MetalLayer: CAMetalLayer {
unowned var common: MacCommon

init(common com: MacCommon) {
common = com
super.init()

pixelFormat = .rgba16Float
backgroundColor = NSColor.black.cgColor
}

// necessary for when the layer containing window changes the screen
override init(layer: Any) {
guard let oldLayer = layer as? MetalLayer else {
fatalError("init(layer: Any) passed an invalid layer")
}
common = oldLayer.common
super.init()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
17 changes: 16 additions & 1 deletion video/out/mac/window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ class Window: NSWindow, NSWindowDelegate {

var unfsContentFrame: NSRect?
var isInFullscreen: Bool = false
var isAnimating: Bool = false
var isMoving: Bool = false
var previousStyleMask: NSWindow.StyleMask = [.titled, .closable, .miniaturizable, .resizable]

var isAnimating: Bool = false
let animationLock: NSCondition = NSCondition()

var unfsContentFramePixel: NSRect { get { return convertToBacking(unfsContentFrame ?? NSRect(x: 0, y: 0, width: 160, height: 90)) } }
var framePixel: NSRect { get { return convertToBacking(frame) } }

Expand Down Expand Up @@ -115,7 +117,9 @@ class Window: NSWindow, NSWindowDelegate {
return
}

animationLock.lock()
isAnimating = true
animationLock.unlock()

targetScreen = common.getTargetScreen(forFullscreen: !isInFullscreen)
if targetScreen == nil && previousScreen == nil {
Expand Down Expand Up @@ -224,7 +228,10 @@ class Window: NSWindow, NSWindowDelegate {
}, completionHandler: nil )
}

animationLock.lock()
isAnimating = false
animationLock.signal()
animationLock.unlock()
common.windowDidEndAnimation()
}

Expand Down Expand Up @@ -265,6 +272,14 @@ class Window: NSWindow, NSWindowDelegate {
common.windowSetToWindow()
}

func waitForAnimation() {
animationLock.lock()
while(isAnimating){
animationLock.wait()
}
animationLock.unlock()
}

func getFsAnimationDuration(_ def: Double) -> Double {
let duration = mpv?.macOpts.macos_fs_animation_duration ?? -1
if duration < 0 {
Expand Down
Loading