summaryrefslogtreecommitdiffstats
path: root/xbmc/windowing/osx/VideoSyncOsx.mm
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/windowing/osx/VideoSyncOsx.mm')
-rw-r--r--xbmc/windowing/osx/VideoSyncOsx.mm148
1 files changed, 148 insertions, 0 deletions
diff --git a/xbmc/windowing/osx/VideoSyncOsx.mm b/xbmc/windowing/osx/VideoSyncOsx.mm
new file mode 100644
index 0000000..d19e724
--- /dev/null
+++ b/xbmc/windowing/osx/VideoSyncOsx.mm
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2005-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#include "VideoSyncOsx.h"
+
+#include "ServiceBroker.h"
+#include "utils/MathUtils.h"
+#include "utils/TimeUtils.h"
+#include "utils/log.h"
+#include "windowing/GraphicContext.h"
+#include "windowing/WinSystem.h"
+
+#include "platform/darwin/osx/CocoaInterface.h"
+
+#include <CoreVideo/CVHostTime.h>
+#include <QuartzCore/CVDisplayLink.h>
+#include <unistd.h>
+
+using namespace std::chrono_literals;
+
+bool CVideoSyncOsx::Setup(PUPDATECLOCK func)
+{
+ CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} setting up OSX", __FUNCTION__);
+
+ //init the vblank timestamp
+ m_LastVBlankTime = 0;
+ UpdateClock = func;
+ m_displayLost = false;
+ m_displayReset = false;
+ m_lostEvent.Reset();
+
+ CServiceBroker::GetWinSystem()->Register(this);
+
+ return true;
+}
+
+void CVideoSyncOsx::Run(CEvent& stopEvent)
+{
+ InitDisplayLink();
+
+ //because cocoa has a vblank callback, we just keep sleeping until we're asked to stop the thread
+ while(!stopEvent.Signaled() && !m_displayLost && !m_displayReset)
+ {
+ usleep(100000);
+ }
+
+ m_lostEvent.Set();
+
+ while(!stopEvent.Signaled() && m_displayLost && !m_displayReset)
+ {
+ usleep(10000);
+ }
+
+ DeinitDisplayLink();
+}
+
+void CVideoSyncOsx::Cleanup()
+{
+ CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} cleaning up OSX", __FUNCTION__);
+ m_lostEvent.Set();
+ m_LastVBlankTime = 0;
+ CServiceBroker::GetWinSystem()->Unregister(this);
+}
+
+float CVideoSyncOsx::GetFps()
+{
+ m_fps = CServiceBroker::GetWinSystem()->GetGfxContext().GetFPS();
+ CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} Detected refreshrate: {:f} hertz", __FUNCTION__, m_fps);
+ return m_fps;
+}
+
+void CVideoSyncOsx::RefreshChanged()
+{
+ m_displayReset = true;
+}
+
+void CVideoSyncOsx::OnLostDisplay()
+{
+ if (!m_displayLost)
+ {
+ m_displayLost = true;
+ m_lostEvent.Wait(1000ms);
+ }
+}
+
+void CVideoSyncOsx::OnResetDisplay()
+{
+ m_displayReset = true;
+}
+
+void CVideoSyncOsx::VblankHandler(int64_t nowtime, uint32_t timebase)
+{
+ int NrVBlanks;
+ double VBlankTime;
+ int64_t Now = CurrentHostCounter();
+
+ if (m_LastVBlankTime != 0)
+ {
+ VBlankTime = (double)(nowtime - m_LastVBlankTime) / (double)timebase;
+ NrVBlanks = MathUtils::round_int(VBlankTime * static_cast<double>(m_fps));
+
+ //update the vblank timestamp, update the clock and send a signal that we got a vblank
+ UpdateClock(NrVBlanks, Now, m_refClock);
+ }
+
+ //save the timestamp of this vblank so we can calculate how many happened next time
+ m_LastVBlankTime = nowtime;
+}
+
+// Called by the Core Video Display Link whenever it's appropriate to render a frame.
+static CVReturn DisplayLinkCallBack(CVDisplayLinkRef displayLink, const CVTimeStamp* inNow, const CVTimeStamp* inOutputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
+{
+ @autoreleasepool
+ {
+ CVideoSyncOsx* VideoSyncOsx = reinterpret_cast<CVideoSyncOsx*>(displayLinkContext);
+
+ if (inOutputTime->flags & kCVTimeStampHostTimeValid)
+ VideoSyncOsx->VblankHandler(inOutputTime->hostTime, CVGetHostClockFrequency());
+ else
+ VideoSyncOsx->VblankHandler(CVGetCurrentHostTime(), CVGetHostClockFrequency());
+ }
+
+ return kCVReturnSuccess;
+}
+
+bool CVideoSyncOsx::InitDisplayLink()
+{
+ bool ret = true;
+ CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} setting up displaylink", __FUNCTION__);
+
+ if (!Cocoa_CVDisplayLinkCreate((void*)DisplayLinkCallBack, reinterpret_cast<void*>(this)))
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncOsx::{} Cocoa_CVDisplayLinkCreate failed", __FUNCTION__);
+ ret = false;
+ }
+ return ret;
+}
+
+void CVideoSyncOsx::DeinitDisplayLink()
+{
+ Cocoa_CVDisplayLinkRelease();
+}
+