mirror of
https://github.com/mpv-player/mpv
synced 2025-03-25 04:38:01 +00:00
vo_gpu/vo_gpu_next: add vulkan support for macOS
add support for vulkan through metal and a translation layer like MoltenVK. also add the possibility to use different render timing modes for testing. i still consider this experimental atm.
This commit is contained in:
parent
bc66de2834
commit
78d43740f5
@ -6273,6 +6273,18 @@ them.
|
||||
|
||||
macOS only.
|
||||
|
||||
``--macos-render-timer=<timer>``
|
||||
Sets the mode (default: callback) for syncing the rendering of frames to the display's
|
||||
vertical refresh rate.
|
||||
macOS and Vulkan (macvk) only.
|
||||
|
||||
``<timer>`` can be one of the following:
|
||||
|
||||
:callback: Syncs to the CVDisplayLink callback
|
||||
:precise: Syncs to the time of the next vertical display refresh reported by the
|
||||
CVDisplayLink callback provided information
|
||||
:system: No manual syncing, depend on the layer mechanic and the next drawable
|
||||
|
||||
``--android-surface-size=<WxH>``
|
||||
Set dimensions of the rendering surface used by the Android gpu context.
|
||||
Needs to be set by the embedding application if the dimensions change during
|
||||
@ -6324,6 +6336,8 @@ them.
|
||||
X11/EGL
|
||||
android
|
||||
Android/EGL. Requires ``--wid`` be set to an ``android.view.Surface``.
|
||||
macvk
|
||||
Vulkan on macOS with a metal surface through a translation layer (experimental)
|
||||
|
||||
``--gpu-api=<type>``
|
||||
Controls which type of graphics APIs will be accepted:
|
||||
|
15
meson.build
15
meson.build
@ -1546,12 +1546,14 @@ swift = get_option('swift-build').require(
|
||||
darwin and macos_sdk_version.version_compare('>=10.10') and swift_ver.version_compare('>=4.1'),
|
||||
error_message: 'A suitable macos sdk version or swift version could not be found!',
|
||||
)
|
||||
features += {'swift': swift.allowed()}
|
||||
|
||||
swift_sources = []
|
||||
if cocoa.found() and swift.allowed()
|
||||
if features['cocoa'] and features['swift']
|
||||
swift_sources += files('osdep/macos/libmpv_helper.swift',
|
||||
'osdep/macos/log_helper.swift',
|
||||
'osdep/macos/mpv_helper.swift',
|
||||
'osdep/macos/precise_timer.swift',
|
||||
'osdep/macos/swift_compat.swift',
|
||||
'osdep/macos/swift_extensions.swift',
|
||||
'video/out/mac/common.swift',
|
||||
@ -1561,7 +1563,7 @@ if cocoa.found() and swift.allowed()
|
||||
endif
|
||||
|
||||
macos_cocoa_cb = get_option('macos-cocoa-cb').require(
|
||||
features['cocoa'] and swift.allowed(),
|
||||
features['cocoa'] and features['swift'],
|
||||
error_message: 'Either cocoa or swift could not be found!',
|
||||
)
|
||||
features += {'macos-cocoa-cb': macos_cocoa_cb.allowed()}
|
||||
@ -1569,9 +1571,14 @@ 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'] and features['swift']
|
||||
swift_sources += files('video/out/mac_common.swift',
|
||||
'video/out/mac/metal_layer.swift')
|
||||
sources += files('video/out/vulkan/context_mac.m')
|
||||
endif
|
||||
|
||||
macos_media_player = get_option('macos-media-player').require(
|
||||
macos_10_12_2_features.allowed() and swift.allowed(),
|
||||
macos_10_12_2_features.allowed() and features['swift'],
|
||||
error_message: 'Either the macos sdk version is not at least 10.12.2 or swift was not found!',
|
||||
)
|
||||
features += {'macos-media-player': macos_media_player.allowed()}
|
||||
@ -1579,7 +1586,7 @@ if features['macos-media-player']
|
||||
swift_sources += files('osdep/macos/remote_command_center.swift')
|
||||
endif
|
||||
|
||||
if swift.allowed() and swift_sources.length() > 0
|
||||
if features['swift'] and swift_sources.length() > 0
|
||||
subdir('osdep')
|
||||
endif
|
||||
|
||||
|
@ -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
|
||||
// compiler doesn't include the needed header in our generated header file
|
||||
// including frameworks here again doesn't make sense, but otherwise the swift
|
||||
// compiler doesn't include the needed headers in our generated header file
|
||||
#import <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#include "player/client.h"
|
||||
#include "video/out/libmpv.h"
|
||||
|
153
osdep/macos/precise_timer.swift
Normal file
153
osdep/macos/precise_timer.swift
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
struct Timing {
|
||||
let time: UInt64
|
||||
let closure: () -> ()
|
||||
}
|
||||
|
||||
class PreciseTimer {
|
||||
unowned var common: Common
|
||||
var mpv: MPVHelper? { get { return common.mpv } }
|
||||
|
||||
let nanoPerSecond: Double = 1e+9
|
||||
let machToNano: Double = {
|
||||
var timebase: mach_timebase_info = mach_timebase_info()
|
||||
mach_timebase_info(&timebase)
|
||||
return Double(timebase.numer) / Double(timebase.denom)
|
||||
}()
|
||||
|
||||
let condition = NSCondition()
|
||||
var events: [Timing] = []
|
||||
var isRunning: Bool = true
|
||||
var isHighPrecision: Bool = false
|
||||
|
||||
var thread: pthread_t!
|
||||
var threadPort: thread_port_t = thread_port_t()
|
||||
let policyFlavor = thread_policy_flavor_t(THREAD_TIME_CONSTRAINT_POLICY)
|
||||
let policyCount = MemoryLayout<thread_time_constraint_policy>.size /
|
||||
MemoryLayout<integer_t>.size
|
||||
var typeNumber: mach_msg_type_number_t {
|
||||
return mach_msg_type_number_t(policyCount)
|
||||
}
|
||||
var threadAttr: pthread_attr_t = {
|
||||
var attr = pthread_attr_t()
|
||||
var param = sched_param()
|
||||
pthread_attr_init(&attr)
|
||||
param.sched_priority = sched_get_priority_max(SCHED_FIFO)
|
||||
pthread_attr_setschedparam(&attr, ¶m)
|
||||
pthread_attr_setschedpolicy(&attr, SCHED_FIFO)
|
||||
return attr
|
||||
}()
|
||||
|
||||
init?(common com: Common) {
|
||||
common = com
|
||||
|
||||
pthread_create(&thread, &threadAttr, entryC, MPVHelper.bridge(obj: self))
|
||||
if thread == nil {
|
||||
common.log.sendWarning("Couldn't create pthread for high precision timer")
|
||||
return nil
|
||||
}
|
||||
|
||||
threadPort = pthread_mach_thread_np(thread)
|
||||
}
|
||||
|
||||
func updatePolicy(periodSeconds: Double = 1 / 60.0) {
|
||||
let period = periodSeconds * nanoPerSecond / machToNano
|
||||
var policy = thread_time_constraint_policy(
|
||||
period: UInt32(period),
|
||||
computation: UInt32(0.75 * period),
|
||||
constraint: UInt32(0.85 * period),
|
||||
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()
|
||||
pthread_kill(thread, SIGALRM)
|
||||
pthread_join(thread, nil)
|
||||
}
|
||||
|
||||
func scheduleAt(time: UInt64, closure: @escaping () -> ()) {
|
||||
condition.lock()
|
||||
let firstEventTime = events.first?.time ?? 0
|
||||
let lastEventTime = events.last?.time ?? 0
|
||||
events.append(Timing(time: time, closure: closure))
|
||||
|
||||
if lastEventTime > time {
|
||||
events.sort{ $0.time < $1.time }
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
guard let event = events.first else {
|
||||
continue
|
||||
}
|
||||
condition.unlock()
|
||||
|
||||
mach_wait_until(event.time)
|
||||
|
||||
condition.lock()
|
||||
if events.first?.time == event.time && isRunning {
|
||||
event.closure()
|
||||
events.removeFirst()
|
||||
}
|
||||
condition.unlock()
|
||||
}
|
||||
}
|
||||
}
|
@ -26,6 +26,12 @@ enum {
|
||||
FRAME_WHOLE,
|
||||
};
|
||||
|
||||
enum {
|
||||
RENDER_TIMER_CALLBACK = 0,
|
||||
RENDER_TIMER_PRECISE,
|
||||
RENDER_TIMER_SYSTEM,
|
||||
};
|
||||
|
||||
struct macos_opts {
|
||||
int macos_title_bar_style;
|
||||
int macos_title_bar_appearance;
|
||||
@ -35,6 +41,7 @@ struct macos_opts {
|
||||
bool macos_force_dedicated_gpu;
|
||||
int macos_app_activation_policy;
|
||||
int macos_geometry_calculation;
|
||||
int macos_render_timer;
|
||||
int cocoa_cb_sw_renderer;
|
||||
bool cocoa_cb_10bit_context;
|
||||
};
|
||||
|
@ -67,6 +67,9 @@ const struct m_sub_options macos_conf = {
|
||||
{"regular", 0}, {"accessory", 1}, {"prohibited", 2})},
|
||||
{"macos-geometry-calculation", OPT_CHOICE(macos_geometry_calculation,
|
||||
{"visible", FRAME_VISIBLE}, {"whole", FRAME_WHOLE})},
|
||||
{"macos-render-timer", OPT_CHOICE(macos_render_timer,
|
||||
{"callback", RENDER_TIMER_CALLBACK}, {"precise", RENDER_TIMER_PRECISE},
|
||||
{"system", RENDER_TIMER_SYSTEM})},
|
||||
{"cocoa-cb-sw-renderer", OPT_CHOICE(cocoa_cb_sw_renderer,
|
||||
{"auto", -1}, {"no", 0}, {"yes", 1})},
|
||||
{"cocoa-cb-10bit-context", OPT_BOOL(cocoa_cb_10bit_context)},
|
||||
|
@ -51,6 +51,7 @@ 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_display;
|
||||
extern const struct ra_ctx_fns ra_ctx_vulkan_mac;
|
||||
|
||||
/* Direct3D 11 */
|
||||
extern const struct ra_ctx_fns ra_ctx_d3d11;
|
||||
@ -113,6 +114,9 @@ static const struct ra_ctx_fns *contexts[] = {
|
||||
#if HAVE_VK_KHR_DISPLAY
|
||||
&ra_ctx_vulkan_display,
|
||||
#endif
|
||||
#if HAVE_COCOA && HAVE_SWIFT
|
||||
&ra_ctx_vulkan_mac,
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* No API contexts: */
|
||||
|
43
video/out/mac/metal_layer.swift
Normal file
43
video/out/mac/metal_layer.swift
Normal file
@ -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")
|
||||
}
|
||||
}
|
177
video/out/mac_common.swift
Normal file
177
video/out/mac_common.swift
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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 MacCommon: Common {
|
||||
@objc var layer: MetalLayer?
|
||||
|
||||
var timer: PreciseTimer?
|
||||
var swapTime: UInt64 = 0
|
||||
let swapLock: NSCondition = NSCondition()
|
||||
|
||||
var needsICCUpdate: Bool = false
|
||||
|
||||
@objc init(_ vo: UnsafeMutablePointer<vo>) {
|
||||
let newlog = mp_log_new(vo, vo.pointee.log, "mac")
|
||||
super.init(newlog)
|
||||
mpv = MPVHelper(vo, log)
|
||||
timer = PreciseTimer(common: self)
|
||||
|
||||
DispatchQueue.main.sync {
|
||||
layer = MetalLayer(common: self)
|
||||
initMisc(vo)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func config(_ vo: UnsafeMutablePointer<vo>) -> Bool {
|
||||
mpv?.vo = vo
|
||||
|
||||
DispatchQueue.main.sync {
|
||||
let previousActiveApp = getActiveApp()
|
||||
initApp()
|
||||
|
||||
let (_, _, wr) = getInitProperties(vo)
|
||||
|
||||
guard let layer = self.layer else {
|
||||
log.sendError("Something went wrong, no MetalLayer was initialized")
|
||||
exit(1)
|
||||
}
|
||||
|
||||
if window == nil {
|
||||
initView(vo, layer)
|
||||
initWindow(vo, previousActiveApp)
|
||||
initWindowState()
|
||||
}
|
||||
|
||||
if !NSEqualSizes(window?.unfsContentFramePixel.size ?? NSZeroSize, wr.size) {
|
||||
window?.updateSize(wr.size)
|
||||
}
|
||||
|
||||
windowDidResize()
|
||||
needsICCUpdate = true
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@objc func uninit(_ vo: UnsafeMutablePointer<vo>) {
|
||||
window?.waitForAnimation()
|
||||
|
||||
timer?.terminate()
|
||||
|
||||
DispatchQueue.main.sync {
|
||||
window?.delegate = nil
|
||||
window?.close()
|
||||
|
||||
uninitCommon()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func swapBuffer() {
|
||||
if mpv?.macOpts.macos_render_timer ?? Int32(RENDER_TIMER_CALLBACK) != RENDER_TIMER_SYSTEM {
|
||||
swapLock.lock()
|
||||
while(swapTime < 1) {
|
||||
swapLock.wait()
|
||||
}
|
||||
swapTime = 0
|
||||
swapLock.unlock()
|
||||
}
|
||||
|
||||
if needsICCUpdate {
|
||||
needsICCUpdate = false
|
||||
updateICCProfile()
|
||||
}
|
||||
}
|
||||
|
||||
func updateRenderSize(_ size: NSSize) {
|
||||
mpv?.vo.pointee.dwidth = Int32(size.width)
|
||||
mpv?.vo.pointee.dheight = Int32(size.height)
|
||||
flagEvents(VO_EVENT_RESIZE | VO_EVENT_EXPOSE)
|
||||
}
|
||||
|
||||
override func displayLinkCallback(_ displayLink: CVDisplayLink,
|
||||
_ inNow: UnsafePointer<CVTimeStamp>,
|
||||
_ inOutputTime: UnsafePointer<CVTimeStamp>,
|
||||
_ flagsIn: CVOptionFlags,
|
||||
_ flagsOut: UnsafeMutablePointer<CVOptionFlags>) -> CVReturn
|
||||
{
|
||||
let frameTimer = mpv?.macOpts.macos_render_timer ?? Int32(RENDER_TIMER_CALLBACK)
|
||||
let signalSwap = { [self] in
|
||||
swapLock.lock()
|
||||
swapTime += 1
|
||||
swapLock.signal()
|
||||
swapLock.unlock()
|
||||
}
|
||||
|
||||
if frameTimer != RENDER_TIMER_SYSTEM {
|
||||
if let timer = self.timer, frameTimer == RENDER_TIMER_PRECISE {
|
||||
timer.scheduleAt(time: inOutputTime.pointee.hostTime, closure: signalSwap)
|
||||
return kCVReturnSuccess
|
||||
}
|
||||
|
||||
signalSwap()
|
||||
}
|
||||
|
||||
return kCVReturnSuccess
|
||||
}
|
||||
|
||||
override func startDisplayLink(_ vo: UnsafeMutablePointer<vo>) {
|
||||
super.startDisplayLink(vo)
|
||||
timer?.updatePolicy(periodSeconds: 1 / currentFps())
|
||||
}
|
||||
|
||||
override func updateDisplaylink() {
|
||||
super.updateDisplaylink()
|
||||
timer?.updatePolicy(periodSeconds: 1 / currentFps())
|
||||
}
|
||||
|
||||
override func lightSensorUpdate() {
|
||||
flagEvents(VO_EVENT_AMBIENT_LIGHTING_CHANGED)
|
||||
}
|
||||
|
||||
@objc override func updateICCProfile() {
|
||||
guard let colorSpace = window?.screen?.colorSpace else {
|
||||
log.sendWarning("Couldn't update ICC Profile, no color space available")
|
||||
return
|
||||
}
|
||||
|
||||
if #available(macOS 10.11, *) {
|
||||
layer?.colorspace = colorSpace.cgColorSpace
|
||||
}
|
||||
|
||||
flagEvents(VO_EVENT_ICC_PROFILE_CHANGED)
|
||||
}
|
||||
|
||||
override func windowDidResize() {
|
||||
guard let window = window else {
|
||||
log.sendWarning("No window available on window resize event")
|
||||
return
|
||||
}
|
||||
|
||||
updateRenderSize(window.framePixel.size)
|
||||
}
|
||||
|
||||
override func windowDidChangeScreenProfile() {
|
||||
needsICCUpdate = true
|
||||
}
|
||||
|
||||
override func windowDidChangeBackingProperties() {
|
||||
layer?.contentsScale = window?.backingScaleFactor ?? 1
|
||||
windowDidResize()
|
||||
}
|
||||
}
|
@ -22,6 +22,10 @@
|
||||
#if HAVE_WIN32_DESKTOP
|
||||
#define VK_USE_PLATFORM_WIN32_KHR
|
||||
#endif
|
||||
#if HAVE_COCOA
|
||||
#define VK_USE_PLATFORM_MACOS_MVK
|
||||
#define VK_USE_PLATFORM_METAL_EXT
|
||||
#endif
|
||||
|
||||
#include <libplacebo/vulkan.h>
|
||||
|
||||
|
119
video/out/vulkan/context_mac.m
Normal file
119
video/out/vulkan/context_mac.m
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "video/out/gpu/context.h"
|
||||
#include "osdep/macOS_swift.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "context.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct priv {
|
||||
struct mpvk_ctx vk;
|
||||
MacCommon *vo_mac;
|
||||
};
|
||||
|
||||
static void mac_vk_uninit(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
|
||||
ra_vk_ctx_uninit(ctx);
|
||||
mpvk_uninit(&p->vk);
|
||||
[p->vo_mac uninit:ctx->vo];
|
||||
}
|
||||
|
||||
static void mac_vk_swap_buffers(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
[p->vo_mac swapBuffer];
|
||||
}
|
||||
|
||||
static bool mac_vk_init(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
struct mpvk_ctx *vk = &p->vk;
|
||||
int msgl = ctx->opts.probing ? MSGL_V : MSGL_ERR;
|
||||
|
||||
if (!mpvk_init(vk, ctx, VK_EXT_METAL_SURFACE_EXTENSION_NAME))
|
||||
goto error;
|
||||
|
||||
p->vo_mac = [[MacCommon alloc] init:ctx->vo];
|
||||
if (!p->vo_mac)
|
||||
goto error;
|
||||
|
||||
VkMetalSurfaceCreateInfoEXT mac_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK,
|
||||
.pNext = NULL,
|
||||
.flags = 0,
|
||||
.pLayer = p->vo_mac.layer,
|
||||
};
|
||||
|
||||
struct ra_vk_ctx_params params = {
|
||||
.swap_buffers = mac_vk_swap_buffers,
|
||||
};
|
||||
|
||||
VkInstance inst = vk->vkinst->instance;
|
||||
VkResult res = vkCreateMetalSurfaceEXT(inst, &mac_info, NULL, &vk->surface);
|
||||
if (res != VK_SUCCESS) {
|
||||
MP_MSG(ctx, msgl, "Failed creating metal surface\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!ra_vk_ctx_init(ctx, vk, params, VK_PRESENT_MODE_FIFO_KHR))
|
||||
goto error;
|
||||
|
||||
return true;
|
||||
error:
|
||||
if (p->vo_mac)
|
||||
[p->vo_mac uninit:ctx->vo];
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool resize(struct ra_ctx *ctx)
|
||||
{
|
||||
return ra_vk_ctx_resize(ctx, ctx->vo->dwidth, ctx->vo->dheight);
|
||||
}
|
||||
|
||||
static bool mac_vk_reconfig(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
if (![p->vo_mac config:ctx->vo])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static int mac_vk_control(struct ra_ctx *ctx, int *events, int request, void *arg)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
int ret = [p->vo_mac control:ctx->vo events:events request:request data:arg];
|
||||
|
||||
if (*events & VO_EVENT_RESIZE) {
|
||||
if (!resize(ctx))
|
||||
return VO_ERROR;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct ra_ctx_fns ra_ctx_vulkan_mac = {
|
||||
.type = "vulkan",
|
||||
.name = "macvk",
|
||||
.reconfig = mac_vk_reconfig,
|
||||
.control = mac_vk_control,
|
||||
.init = mac_vk_init,
|
||||
.uninit = mac_vk_uninit,
|
||||
};
|
Loading…
Reference in New Issue
Block a user