summaryrefslogtreecommitdiffstats
path: root/video/out/present_sync.c
diff options
context:
space:
mode:
authorDudemanguy <random342@airmail.cc>2022-06-10 11:49:28 -0500
committerDudemanguy <random342@airmail.cc>2022-06-19 18:13:55 +0000
commit7ce26dd3248a45a4d5e0a8c15a981834e7efc733 (patch)
treeb79e41d7b30ceaa8df3d1c64427acb73775916ba /video/out/present_sync.c
parent44ecf83a1bd94f69cbe7e55b900f2502d15d7d5c (diff)
downloadmpv-7ce26dd3248a45a4d5e0a8c15a981834e7efc733.tar.bz2
mpv-7ce26dd3248a45a4d5e0a8c15a981834e7efc733.tar.xz
vo: move wayland presentation to separate files
Wayland had some specific code that it used for implementing the presentation time protocol. It turns out that xorg's present extension is extremely similar, so it would be silly to duplicate this whole mess again. Factor this out to separate, independent code and introduce the mp_present struct which is used for handling the ust/msc values and some other associated values. Also, add in some helper functions so all the dirty details live specifically in present_sync. The only wayland-specific part is actually obtaining ust/msc values. Since only wayland or xorg are expected to use this, add a conditional to the build that only adds this file when either one of those are present. You may observe that sbc is completely omitted. This field existed in wayland, but was completely unused (presentation time doesn't return this). Xorg's present extension also doesn't use this so just get rid of it all together. The actual calculation is slightly altered so it is correct for our purposes. We want to get the presentation event of the last frame that was just occured (this function executes right after the buffer swap). The adjustment is to just remove the vsync_duration subtraction. Also, The overly-complicated queue approach is removed. This has no actual use in practice (on wayland or xorg). Presentation statistics are only ever used after the immediate preceding swap to update vsync timings or thrown away.
Diffstat (limited to 'video/out/present_sync.c')
-rw-r--r--video/out/present_sync.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/video/out/present_sync.c b/video/out/present_sync.c
new file mode 100644
index 0000000000..16d7416d43
--- /dev/null
+++ b/video/out/present_sync.c
@@ -0,0 +1,85 @@
+/*
+ * 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 <time.h>
+
+#include "mpv_talloc.h"
+#include "osdep/timer.h"
+#include "present_sync.h"
+
+/* General nonsense about this mechanism.
+ *
+ * This requires that that caller has access to two, related values:
+ * (ust, msc): clock time and incrementing counter of last vsync (this is
+ * increased continuously, even if we don't swap)
+ *
+ * Note that this concept originates from the GLX_OML_sync_control extension
+ * which includes another parameter: sbc (swap counter of frame that was
+ * last displayed). Both the xorg present extension and wayland's
+ * presentation-time protocol do not include sbc values so they are omitted
+ * from this mechanism. mpv does not need to keep track of sbc calls and can
+ * have reliable presentation without it.
+ */
+
+void present_sync_get_info(struct mp_present *present, struct vo_vsync_info *info)
+{
+ info->vsync_duration = present->vsync_duration;
+ info->skipped_vsyncs = present->last_skipped_vsyncs;
+ info->last_queue_display_time = present->last_queue_display_time;
+}
+
+void present_sync_swap(struct mp_present *present)
+{
+ int64_t ust = present->current_ust;
+ int64_t msc = present->current_msc;
+
+ // Avoid attempting to use any presentation statistics if the ust is 0 or has
+ // not actually updated (i.e. the last_ust is equal to current_ust).
+ if (!ust || ust == present->last_ust) {
+ present->last_skipped_vsyncs = -1;
+ present->vsync_duration = -1;
+ present->last_queue_display_time = -1;
+ return;
+ }
+
+ present->last_skipped_vsyncs = 0;
+
+ int64_t ust_passed = ust ? ust - present->last_ust: 0;
+ present->last_ust = ust;
+ int64_t msc_passed = msc ? msc - present->last_msc: 0;
+ present->last_msc = msc;
+
+ if (msc_passed && ust_passed)
+ present->vsync_duration = ust_passed / msc_passed;
+
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ return;
+ }
+
+ uint64_t now_monotonic = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+ uint64_t ust_mp_time = mp_time_us() - (now_monotonic - ust);
+
+ present->last_queue_display_time = ust_mp_time;
+}
+
+void present_update_sync_values(struct mp_present *present, int64_t ust,
+ int64_t msc)
+{
+ present->current_ust = ust;
+ present->current_msc = msc;
+}