summaryrefslogtreecommitdiffstats
path: root/osdep
diff options
context:
space:
mode:
Diffstat (limited to 'osdep')
-rw-r--r--osdep/macOS_swift_bridge.h5
-rw-r--r--osdep/macos/precise_timer.swift153
-rw-r--r--osdep/macosx_application.h7
-rw-r--r--osdep/macosx_application.m3
4 files changed, 166 insertions, 2 deletions
diff --git a/osdep/macOS_swift_bridge.h b/osdep/macOS_swift_bridge.h
index 29cd8bf016..9407b6fc9b 100644
--- a/osdep/macOS_swift_bridge.h
+++ b/osdep/macOS_swift_bridge.h
@@ -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"
diff --git a/osdep/macos/precise_timer.swift b/osdep/macos/precise_timer.swift
new file mode 100644
index 0000000000..f4ad3bb6b6
--- /dev/null
+++ b/osdep/macos/precise_timer.swift
@@ -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, &param)
+ 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()
+ }
+ }
+}
diff --git a/osdep/macosx_application.h b/osdep/macosx_application.h
index d95940fd31..753b9f033f 100644
--- a/osdep/macosx_application.h
+++ b/osdep/macosx_application.h
@@ -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;
};
diff --git a/osdep/macosx_application.m b/osdep/macosx_application.m
index fc1da01d39..bf60e05389 100644
--- a/osdep/macosx_application.m
+++ b/osdep/macosx_application.m
@@ -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)},