mirror of https://github.com/mpv-player/mpv
mac/vulkan: add support for frame timing via presentation feedback
This commit is contained in:
parent
6df07ce90c
commit
ee6794225d
|
@ -6358,6 +6358,7 @@ them.
|
|||
: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
|
||||
:feedback: Same as precise but uses the presentation feedback core mechanism
|
||||
|
||||
``--android-surface-size=<WxH>``
|
||||
Set dimensions of the rendering surface used by the Android gpu context.
|
||||
|
|
|
@ -1541,6 +1541,7 @@ if features['cocoa'] and features['swift']
|
|||
'osdep/mac/menu_bar.swift',
|
||||
'osdep/mac/option_helper.swift',
|
||||
'osdep/mac/precise_timer.swift',
|
||||
'osdep/mac/presentation.swift',
|
||||
'osdep/mac/swift_compat.swift',
|
||||
'osdep/mac/swift_extensions.swift',
|
||||
'osdep/mac/type_helper.swift',
|
||||
|
|
|
@ -29,9 +29,10 @@ enum {
|
|||
};
|
||||
|
||||
enum {
|
||||
RENDER_TIMER_CALLBACK = 0,
|
||||
RENDER_TIMER_PRECISE,
|
||||
RENDER_TIMER_PRESENTATION_FEEDBACK = -1,
|
||||
RENDER_TIMER_SYSTEM,
|
||||
RENDER_TIMER_CALLBACK,
|
||||
RENDER_TIMER_PRECISE,
|
||||
};
|
||||
|
||||
struct macos_opts {
|
||||
|
|
|
@ -51,7 +51,7 @@ const struct m_sub_options macos_conf = {
|
|||
{"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})},
|
||||
{"system", RENDER_TIMER_SYSTEM}, {"feedback", RENDER_TIMER_PRESENTATION_FEEDBACK})},
|
||||
{"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)},
|
||||
|
@ -61,6 +61,7 @@ const struct m_sub_options macos_conf = {
|
|||
.defaults = &(const struct macos_opts){
|
||||
.macos_title_bar_color = {0, 0, 0, 0},
|
||||
.macos_fs_animation_duration = -1,
|
||||
.macos_render_timer = RENDER_TIMER_CALLBACK,
|
||||
.cocoa_cb_sw_renderer = -1,
|
||||
.cocoa_cb_10bit_context = true
|
||||
},
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
extension Presentation {
|
||||
struct Time {
|
||||
let cvTime: CVTimeStamp
|
||||
var skipped: Int64 = 0
|
||||
var time: Int64 { return mp_time_ns_from_raw_time(mp_raw_time_ns_from_mach(cvTime.hostTime)) }
|
||||
var duration: Int64 {
|
||||
let durationSeconds = Double(cvTime.videoRefreshPeriod) / Double(cvTime.videoTimeScale)
|
||||
return Int64(durationSeconds * Presentation.nanoPerSecond * cvTime.rateScalar)
|
||||
}
|
||||
|
||||
init(_ time: CVTimeStamp) {
|
||||
cvTime = time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Presentation {
|
||||
unowned var common: Common
|
||||
var times: [Time] = []
|
||||
static let nanoPerSecond: Double = 1e+9
|
||||
|
||||
init(common com: Common) {
|
||||
common = com
|
||||
}
|
||||
|
||||
func add(time: CVTimeStamp) {
|
||||
times.append(Time(time))
|
||||
}
|
||||
|
||||
func next() -> Time? {
|
||||
let now = mp_time_ns()
|
||||
let count = times.count
|
||||
times.removeAll(where: { $0.time <= now })
|
||||
var time = times.first
|
||||
time?.skipped = Int64(max(count - times.count - 1, 0))
|
||||
|
||||
return time
|
||||
}
|
||||
}
|
|
@ -36,7 +36,12 @@ void mp_sleep_ns(int64_t ns)
|
|||
|
||||
uint64_t mp_raw_time_ns(void)
|
||||
{
|
||||
return mach_absolute_time() * timebase_ratio_ns;
|
||||
return mp_raw_time_ns_from_mach(mach_absolute_time());
|
||||
}
|
||||
|
||||
uint64_t mp_raw_time_ns_from_mach(uint64_t mach_time)
|
||||
{
|
||||
return mach_time * timebase_ratio_ns;
|
||||
}
|
||||
|
||||
void mp_raw_time_init(void)
|
||||
|
|
|
@ -46,7 +46,12 @@ void mp_time_init(void)
|
|||
|
||||
int64_t mp_time_ns(void)
|
||||
{
|
||||
return mp_raw_time_ns() - raw_time_offset;
|
||||
return mp_time_ns_from_raw_time(mp_raw_time_ns());
|
||||
}
|
||||
|
||||
int64_t mp_time_ns_from_raw_time(uint64_t raw_time)
|
||||
{
|
||||
return raw_time - raw_time_offset;
|
||||
}
|
||||
|
||||
double mp_time_sec(void)
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define MPLAYER_TIMER_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include "config.h"
|
||||
|
||||
// Initialize timer, must be called at least once at start.
|
||||
void mp_time_init(void);
|
||||
|
@ -26,6 +27,9 @@ void mp_time_init(void);
|
|||
// Return time in nanoseconds. Never wraps. Never returns negative values.
|
||||
int64_t mp_time_ns(void);
|
||||
|
||||
// Return time in nanoseconds. Coverts raw time in nanoseconds to mp time, subtracts init offset.
|
||||
int64_t mp_time_ns_from_raw_time(uint64_t raw_time);
|
||||
|
||||
// Return time in seconds. Can have down to 1 nanosecond resolution, but will
|
||||
// be much worse when casted to float.
|
||||
double mp_time_sec(void);
|
||||
|
@ -38,6 +42,11 @@ uint64_t mp_raw_time_ns(void);
|
|||
// Sleep in nanoseconds.
|
||||
void mp_sleep_ns(int64_t ns);
|
||||
|
||||
#if HAVE_DARWIN
|
||||
// Coverts mach time to raw time in nanoseconds and returns it.
|
||||
uint64_t mp_raw_time_ns_from_mach(uint64_t mach_time);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// returns: timer resolution in ns if needed and started successfully, else 0
|
||||
int64_t mp_start_hires_timers(int64_t wait_ns);
|
||||
|
|
|
@ -20,6 +20,7 @@ import Cocoa
|
|||
class MacCommon: Common {
|
||||
@objc var layer: MetalLayer?
|
||||
|
||||
var presentation: Presentation?
|
||||
var timer: PreciseTimer?
|
||||
var swapTime: UInt64 = 0
|
||||
let swapLock: NSCondition = NSCondition()
|
||||
|
@ -30,6 +31,7 @@ class MacCommon: Common {
|
|||
super.init(option, log)
|
||||
self.vo = vo
|
||||
input = InputHelper(vo.pointee.input_ctx, option)
|
||||
presentation = Presentation(common: self)
|
||||
timer = PreciseTimer(common: self)
|
||||
|
||||
DispatchQueue.main.sync {
|
||||
|
@ -89,7 +91,7 @@ class MacCommon: Common {
|
|||
}
|
||||
|
||||
@objc func swapBuffer() {
|
||||
if option.mac.macos_render_timer != RENDER_TIMER_SYSTEM {
|
||||
if option.mac.macos_render_timer > RENDER_TIMER_SYSTEM {
|
||||
swapLock.lock()
|
||||
while(swapTime < 1) {
|
||||
swapLock.wait()
|
||||
|
@ -99,6 +101,15 @@ class MacCommon: Common {
|
|||
}
|
||||
}
|
||||
|
||||
@objc func fillVsync(info: UnsafeMutablePointer<vo_vsync_info>) {
|
||||
if option.mac.macos_render_timer != RENDER_TIMER_PRESENTATION_FEEDBACK { return }
|
||||
|
||||
let next = presentation?.next()
|
||||
info.pointee.vsync_duration = next?.duration ?? -1
|
||||
info.pointee.skipped_vsyncs = next?.skipped ?? -1
|
||||
info.pointee.last_queue_display_time = next?.time ?? -1
|
||||
}
|
||||
|
||||
override func displayLinkCallback(_ displayLink: CVDisplayLink,
|
||||
_ inNow: UnsafePointer<CVTimeStamp>,
|
||||
_ inOutputTime: UnsafePointer<CVTimeStamp>,
|
||||
|
@ -112,13 +123,18 @@ class MacCommon: Common {
|
|||
self.swapLock.unlock()
|
||||
}
|
||||
|
||||
if option.mac.macos_render_timer != RENDER_TIMER_SYSTEM {
|
||||
if option.mac.macos_render_timer > RENDER_TIMER_SYSTEM {
|
||||
if let timer = self.timer, option.mac.macos_render_timer == RENDER_TIMER_PRECISE {
|
||||
timer.scheduleAt(time: inOutputTime.pointee.hostTime, closure: signalSwap)
|
||||
return kCVReturnSuccess
|
||||
}
|
||||
|
||||
signalSwap()
|
||||
return kCVReturnSuccess
|
||||
}
|
||||
|
||||
if option.mac.macos_render_timer == RENDER_TIMER_PRESENTATION_FEEDBACK {
|
||||
presentation?.add(time: inOutputTime.pointee)
|
||||
}
|
||||
|
||||
return kCVReturnSuccess
|
||||
|
|
|
@ -44,6 +44,12 @@ static void mac_vk_swap_buffers(struct ra_ctx *ctx)
|
|||
[p->vo_mac swapBuffer];
|
||||
}
|
||||
|
||||
static void mac_vk_get_vsync(struct ra_ctx *ctx, struct vo_vsync_info *info)
|
||||
{
|
||||
struct priv *p = ctx->priv;
|
||||
[p->vo_mac fillVsyncWithInfo:info];
|
||||
}
|
||||
|
||||
static bool mac_vk_init(struct ra_ctx *ctx)
|
||||
{
|
||||
struct priv *p = ctx->priv = talloc_zero(ctx, struct priv);
|
||||
|
@ -66,6 +72,7 @@ static bool mac_vk_init(struct ra_ctx *ctx)
|
|||
|
||||
struct ra_vk_ctx_params params = {
|
||||
.swap_buffers = mac_vk_swap_buffers,
|
||||
.get_vsync = mac_vk_get_vsync,
|
||||
};
|
||||
|
||||
VkInstance inst = vk->vkinst->instance;
|
||||
|
|
Loading…
Reference in New Issue