aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRainer Hochecker <fernetmenta@online.de>2014-10-17 08:55:16 +0200
committerRainer Hochecker <fernetmenta@online.de>2014-10-31 21:45:03 +0100
commitce924e98a4f6be2e31dec8fa5846307cbe56f273 (patch)
tree08feb0577fc90f9bae9abe3874a2d21fc108db5a
parenteda7cc530f9770879a771252179fe4872b878ddf (diff)
videorefclock: refactoring
-rw-r--r--Kodi.xcodeproj/project.pbxproj20
-rw-r--r--Makefile.in1
-rw-r--r--project/VS2010Express/XBMC.vcxproj5
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters14
-rw-r--r--xbmc/cores/dvdplayer/DVDPlayerVideo.cpp5
-rw-r--r--xbmc/osx/IOSEAGLView.mm3
-rw-r--r--xbmc/settings/AdvancedSettings.cpp4
-rw-r--r--xbmc/settings/AdvancedSettings.h3
-rw-r--r--xbmc/video/VideoReferenceClock.cpp879
-rw-r--r--xbmc/video/VideoReferenceClock.h91
-rw-r--r--xbmc/video/videosync/Makefile7
-rw-r--r--xbmc/video/videosync/VideoSync.h35
-rw-r--r--xbmc/video/videosync/VideoSyncCocoa.cpp150
-rw-r--r--xbmc/video/videosync/VideoSyncCocoa.h37
-rw-r--r--xbmc/video/videosync/VideoSyncD3D.cpp208
-rw-r--r--xbmc/video/videosync/VideoSyncD3D.h50
-rw-r--r--xbmc/video/videosync/VideoSyncGLX.cpp287
-rw-r--r--xbmc/video/videosync/VideoSyncGLX.h55
-rw-r--r--xbmc/windowing/osx/WinSystemIOS.h5
-rw-r--r--xbmc/windowing/osx/WinSystemIOS.mm11
20 files changed, 935 insertions, 935 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index 82e3cea046..bf49f6402f 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -1285,6 +1285,9 @@
DF93D7F61444B568007C6459 /* HDHomeRunDirectory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF93D7F51444B568007C6459 /* HDHomeRunDirectory.cpp */; };
DF98D98C1434F47D00A6EBE1 /* SkinVariable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF98D98A1434F47D00A6EBE1 /* SkinVariable.cpp */; };
DF9A71EE1639C8F6005ECB2E /* HTTPFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF9A71EC1639C8F6005ECB2E /* HTTPFile.cpp */; };
+ DFA0E8C519FD6BEE00269A92 /* VideoSyncCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA0E8C319FD6BEE00269A92 /* VideoSyncCocoa.cpp */; };
+ DFA0E8C719FD7BD100269A92 /* VideoSyncCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA0E8C319FD6BEE00269A92 /* VideoSyncCocoa.cpp */; };
+ DFA0E8C819FD7BD100269A92 /* VideoSyncCocoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA0E8C319FD6BEE00269A92 /* VideoSyncCocoa.cpp */; };
DFA8157E16713B1200E4E597 /* WakeOnAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFA8157C16713B1200E4E597 /* WakeOnAccess.cpp */; };
DFAB049813F8376700B70BFB /* InertialScrollingHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAB049613F8376700B70BFB /* InertialScrollingHandler.cpp */; };
DFAF6A4F16EBAE3800D6AE12 /* RssManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DFAF6A4D16EBAE3800D6AE12 /* RssManager.cpp */; };
@@ -5012,6 +5015,9 @@
DF98D98B1434F47D00A6EBE1 /* SkinVariable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SkinVariable.h; sourceTree = "<group>"; };
DF9A71EC1639C8F6005ECB2E /* HTTPFile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPFile.cpp; sourceTree = "<group>"; };
DF9A71ED1639C8F6005ECB2E /* HTTPFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPFile.h; sourceTree = "<group>"; };
+ DFA0E8C219FD6BEE00269A92 /* VideoSync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VideoSync.h; path = videosync/VideoSync.h; sourceTree = "<group>"; };
+ DFA0E8C319FD6BEE00269A92 /* VideoSyncCocoa.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VideoSyncCocoa.cpp; path = videosync/VideoSyncCocoa.cpp; sourceTree = "<group>"; };
+ DFA0E8C419FD6BEE00269A92 /* VideoSyncCocoa.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = VideoSyncCocoa.h; path = videosync/VideoSyncCocoa.h; sourceTree = "<group>"; };
DFA8157C16713B1200E4E597 /* WakeOnAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WakeOnAccess.cpp; sourceTree = "<group>"; };
DFA8157D16713B1200E4E597 /* WakeOnAccess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WakeOnAccess.h; sourceTree = "<group>"; };
DFAB049613F8376700B70BFB /* InertialScrollingHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InertialScrollingHandler.cpp; sourceTree = "<group>"; };
@@ -7213,6 +7219,7 @@
isa = PBXGroup;
children = (
43FAC88612D6363B00F67914 /* dialogs */,
+ DFA0E8C619FD6BFC00269A92 /* videosync */,
43FAC88812D6364800F67914 /* windows */,
7C62F24010505BC7002AD2C1 /* Bookmark.cpp */,
7C62F24110505BC7002AD2C1 /* Bookmark.h */,
@@ -8307,6 +8314,16 @@
path = view;
sourceTree = "<group>";
};
+ DFA0E8C619FD6BFC00269A92 /* videosync */ = {
+ isa = PBXGroup;
+ children = (
+ DFA0E8C219FD6BEE00269A92 /* VideoSync.h */,
+ DFA0E8C319FD6BEE00269A92 /* VideoSyncCocoa.cpp */,
+ DFA0E8C419FD6BEE00269A92 /* VideoSyncCocoa.h */,
+ );
+ name = videosync;
+ sourceTree = "<group>";
+ };
DFB15B1F15F8FB8100CDF0DE /* osx */ = {
isa = PBXGroup;
children = (
@@ -11646,6 +11663,7 @@
7CCDA209192753E30074CF51 /* ContentDirectorywSearchSCPD.cpp in Sources */,
7CCDA214192753E30074CF51 /* PltDidl.cpp in Sources */,
7CCDA21D192753E30074CF51 /* PltFileMediaServer.cpp in Sources */,
+ DFA0E8C519FD6BEE00269A92 /* VideoSyncCocoa.cpp in Sources */,
7CCDA226192753E30074CF51 /* PltMediaBrowser.cpp in Sources */,
7CCDA22F192753E30074CF51 /* PltMediaCache.cpp in Sources */,
7CCDA238192753E30074CF51 /* PltMediaItem.cpp in Sources */,
@@ -11978,6 +11996,7 @@
DFF0F16F17528350002DA3A4 /* DVDDemuxPVRClient.cpp in Sources */,
DFF0F17017528350002DA3A4 /* DVDDemuxShoutcast.cpp in Sources */,
DFF0F17117528350002DA3A4 /* DVDDemuxUtils.cpp in Sources */,
+ DFA0E8C819FD7BD100269A92 /* VideoSyncCocoa.cpp in Sources */,
DFF0F17217528350002DA3A4 /* DVDDemuxVobsub.cpp in Sources */,
DFF0F17317528350002DA3A4 /* DVDFactoryDemuxer.cpp in Sources */,
DFF0F17417528350002DA3A4 /* DVDFactoryInputStream.cpp in Sources */,
@@ -13661,6 +13680,7 @@
E49913DA174E5F8D00741B6D /* Picture.cpp in Sources */,
E49913DB174E5F8D00741B6D /* PictureInfoLoader.cpp in Sources */,
E49913DC174E5F8D00741B6D /* PictureInfoTag.cpp in Sources */,
+ DFA0E8C719FD7BD100269A92 /* VideoSyncCocoa.cpp in Sources */,
E49913DD174E5F8D00741B6D /* PictureThumbLoader.cpp in Sources */,
E49913DE174E5F8D00741B6D /* SlideShowPicture.cpp in Sources */,
E49913DF174E5F8D00741B6D /* PlayList.cpp in Sources */,
diff --git a/Makefile.in b/Makefile.in
index bd28e52ff2..1ce9039ac6 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -96,6 +96,7 @@ DIRECTORY_ARCHIVES=$(DVDPLAYER_ARCHIVES) \
xbmc/storage/storage.a \
xbmc/utils/utils.a \
xbmc/video/dialogs/videodialogs.a \
+ xbmc/video/videosync/videosync.a \
xbmc/video/video.a \
xbmc/video/windows/videowindows.a \
xbmc/view/view.a \
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index b33e533115..c29fb2f17b 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -1139,6 +1139,7 @@
<ClCompile Include="..\..\xbmc\utils\win32\Win32Log.cpp" />
<ClCompile Include="..\..\xbmc\utils\XSLTUtils.cpp" />
<ClCompile Include="..\..\xbmc\video\PlayerController.cpp" />
+ <ClCompile Include="..\..\xbmc\video\videosync\VideoSyncD3D.cpp" />
<ClCompile Include="..\..\xbmc\video\VideoThumbLoader.cpp" />
<ClCompile Include="..\..\xbmc\music\MusicThumbLoader.cpp" />
<ClCompile Include="..\..\xbmc\ThumbnailCache.cpp" />
@@ -2025,6 +2026,8 @@
<ClInclude Include="..\..\xbmc\DatabaseManager.h" />
<ClInclude Include="..\..\xbmc\ThumbLoader.h" />
<ClInclude Include="..\..\xbmc\video\PlayerController.h" />
+ <ClInclude Include="..\..\xbmc\video\videosync\VideoSync.h" />
+ <ClInclude Include="..\..\xbmc\video\videosync\VideoSyncD3D.h" />
<ClInclude Include="..\..\xbmc\video\VideoThumbLoader.h" />
<ClInclude Include="..\..\xbmc\music\MusicThumbLoader.h" />
<ClInclude Include="..\..\xbmc\ThumbnailCache.h" />
@@ -2551,4 +2554,4 @@
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project>
+</Project> \ No newline at end of file
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index ca16ec8c1a..dbb9b9d41f 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -319,6 +319,9 @@
<Filter Include="utils\win32">
<UniqueIdentifier>{3adbba6a-6fbf-4192-b215-108d94bde1e0}</UniqueIdentifier>
</Filter>
+ <Filter Include="video\videosync">
+ <UniqueIdentifier>{9775d5c0-c640-4606-a625-e6cdcf9f959e}</UniqueIdentifier>
+ </Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\..\xbmc\win32\pch.cpp">
@@ -3077,6 +3080,9 @@
<ClCompile Include="..\..\xbmc\filesystem\BlurayFile.cpp">
<Filter>filesystem</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\video\videosync\VideoSyncD3D.cpp">
+ <Filter>video\videosync</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\xbmc\win32\pch.h">
@@ -6022,6 +6028,12 @@
<ClInclude Include="..\..\xbmc\filesystem\BlurayFile.h">
<Filter>filesystem</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\video\videosync\VideoSyncD3D.h">
+ <Filter>video\videosync</Filter>
+ </ClInclude>
+ <ClInclude Include="..\..\xbmc\video\videosync\VideoSync.h">
+ <Filter>video\videosync</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
@@ -6067,4 +6079,4 @@
<Filter>interfaces\swig</Filter>
</None>
</ItemGroup>
-</Project>
+</Project> \ No newline at end of file
diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
index e039c2b938..5a758ab714 100644
--- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
@@ -164,7 +164,7 @@ CDVDPlayerVideo::CDVDPlayerVideo( CDVDClock* pClock
CDVDPlayerVideo::~CDVDPlayerVideo()
{
StopThread();
- g_VideoReferenceClock.StopThread();
+ g_VideoReferenceClock.Stop();
}
double CDVDPlayerVideo::GetOutputDelay()
@@ -205,9 +205,6 @@ bool CDVDPlayerVideo::OpenStream( CDVDStreamInfo &hint )
if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") && !g_VideoReferenceClock.IsRunning())
{
g_VideoReferenceClock.Create();
- //we have to wait for the clock to start otherwise alsa can cause trouble
- if (!g_VideoReferenceClock.WaitStarted(2000))
- CLog::Log(LOGDEBUG, "g_VideoReferenceClock didn't start in time");
}
if(m_messageQueue.IsInited())
diff --git a/xbmc/osx/IOSEAGLView.mm b/xbmc/osx/IOSEAGLView.mm
index bf09e90833..50cdf80986 100644
--- a/xbmc/osx/IOSEAGLView.mm
+++ b/xbmc/osx/IOSEAGLView.mm
@@ -36,6 +36,7 @@
#include "utils/TimeUtils.h"
#include "Util.h"
#include "XbmcContext.h"
+#include "WindowingFactory.h"
#undef BOOL
#import <QuartzCore/QuartzCore.h>
@@ -457,7 +458,7 @@
if (animationThread && [animationThread isExecuting] == YES)
{
if (g_VideoReferenceClock.IsRunning())
- g_VideoReferenceClock.VblankHandler(CurrentHostCounter(), displayFPS);
+ g_Windowing.VblankHandler(CurrentHostCounter(), displayFPS);
}
[pool release];
}
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 3aff9f61ad..7d048723ca 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -363,8 +363,6 @@ void CAdvancedSettings::Initialize()
m_bPVRAutoScanIconsUserSet = false;
m_iPVRNumericChannelSwitchTimeout = 1000;
- m_measureRefreshrate = false;
-
m_cacheMemBufferSize = 1024 * 1024 * 20;
m_networkBufferMode = 0; // Default (buffer all internet streams/filesystems)
// the following setting determines the readRate of a player data
@@ -1093,8 +1091,6 @@ void CAdvancedSettings::ParseSettingsFile(const CStdString &file)
XMLUtils::GetInt(pPVR, "numericchannelswitchtimeout", m_iPVRNumericChannelSwitchTimeout, 50, 60000);
}
- XMLUtils::GetBoolean(pRootElement, "measurerefreshrate", m_measureRefreshrate);
-
TiXmlElement* pDatabase = pRootElement->FirstChildElement("videodatabase");
if (pDatabase)
{
diff --git a/xbmc/settings/AdvancedSettings.h b/xbmc/settings/AdvancedSettings.h
index 1d9021e28a..7df586e444 100644
--- a/xbmc/settings/AdvancedSettings.h
+++ b/xbmc/settings/AdvancedSettings.h
@@ -365,9 +365,6 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler
bool m_bPVRAutoScanIconsUserSet; /*!< @brief mark channel icons populated by auto scan as "user set" */
int m_iPVRNumericChannelSwitchTimeout; /*!< @brief time in ms before the numeric dialog auto closes when confirmchannelswitch is disabled */
- bool m_measureRefreshrate; //when true the videoreferenceclock will measure the refreshrate when direct3d is used
- //otherwise it will use the windows refreshrate
-
DatabaseSettings m_databaseMusic; // advanced music database setup
DatabaseSettings m_databaseVideo; // advanced video database setup
DatabaseSettings m_databaseTV; // advanced tv database setup
diff --git a/xbmc/video/VideoReferenceClock.cpp b/xbmc/video/VideoReferenceClock.cpp
index 6d84b60613..fb10282f81 100644
--- a/xbmc/video/VideoReferenceClock.cpp
+++ b/xbmc/video/VideoReferenceClock.cpp
@@ -26,127 +26,60 @@
#include "utils/TimeUtils.h"
#include "utils/StringUtils.h"
#include "threads/SingleLock.h"
+#include "guilib/GraphicContext.h"
+#include "video/videosync/VideoSync.h"
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- #include <sstream>
- #include <X11/extensions/Xrandr.h>
- #include "windowing/WindowingFactory.h"
- #include "guilib/GraphicContext.h"
-#elif defined(TARGET_DARWIN_OSX)
- #include <QuartzCore/CVDisplayLink.h>
- #include "osx/CocoaInterface.h"
-#elif defined(TARGET_DARWIN_IOS)
- #include "windowing/WindowingFactory.h"
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- #pragma comment (lib,"d3d9.lib")
- #if (D3DX_SDK_VERSION >= 42) //aug 2009 sdk and up there is no dxerr9 anymore
- #include <Dxerr.h>
- #pragma comment (lib,"DxErr.lib")
- #else
- #include <dxerr9.h>
- #define DXGetErrorString(hr) DXGetErrorString9(hr)
- #define DXGetErrorDescription(hr) DXGetErrorDescription9(hr)
- #pragma comment (lib,"Dxerr9.lib")
- #endif
- #include "windowing/WindowingFactory.h"
- #include "settings/AdvancedSettings.h"
+#if defined(HAS_GLX)
+#include "video/videosync/VideoSyncGLX.h"
+#endif
+#if defined(TARGET_WINDOWS)
+#include "video/videosync/VideoSyncD3D.h"
+#endif
+#if defined(TARGET_DARWIN)
+#include "video/videosync/VideoSyncCocoa.h"
#endif
using namespace std;
-#if defined(TARGET_WINDOWS) && defined(HAS_DX)
-
- void CD3DCallback::Reset()
- {
- m_devicevalid = true;
- m_deviceused = false;
- }
-
- void CD3DCallback::OnDestroyDevice()
- {
- CSingleLock lock(m_critsection);
- m_devicevalid = false;
- while (m_deviceused)
- {
- lock.Leave();
- m_releaseevent.Wait();
- lock.Enter();
- }
- }
-
- void CD3DCallback::OnCreateDevice()
- {
- CSingleLock lock(m_critsection);
- m_devicevalid = true;
- m_createevent.Set();
- }
-
- void CD3DCallback::Aquire()
- {
- CSingleLock lock(m_critsection);
- while(!m_devicevalid)
- {
- lock.Leave();
- m_createevent.Wait();
- lock.Enter();
- }
- m_deviceused = true;
- }
-
- void CD3DCallback::Release()
- {
- CSingleLock lock(m_critsection);
- m_deviceused = false;
- m_releaseevent.Set();
- }
-
- bool CD3DCallback::IsValid()
- {
- return m_devicevalid;
- }
-
-#endif
-
-CVideoReferenceClock::CVideoReferenceClock() : CThread("VideoReferenceClock")
+CVideoReferenceClock::CVideoReferenceClock() : CThread("RefClock")
{
m_SystemFrequency = CurrentHostFrequency();
m_ClockSpeed = 1.0;
m_ClockOffset = 0;
m_TotalMissedVblanks = 0;
m_UseVblank = false;
- m_Started.Reset();
m_CurrTime = 0;
m_LastIntTime = 0;
m_CurrTimeFract = 0.0;
- m_LastRefreshTime = 0;
m_fineadjust = 0.0;
m_RefreshRate = 0.0;
- m_PrevRefreshRate = 0;
m_MissedVblanks = 0;
m_RefreshChanged = 0;
m_VblankTime = 0;
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- m_glXWaitVideoSyncSGI = NULL;
- m_glXGetVideoSyncSGI = NULL;
- m_Dpy = NULL;
- m_vInfo = NULL;
- m_Window = 0;
- m_Context = NULL;
-#endif
+ m_pVideoSync = NULL;
}
CVideoReferenceClock::~CVideoReferenceClock()
{
-#if defined(HAS_GLX)
- // some ATI voodoo, if we don't close the display, we crash on exit
- if (m_Dpy)
+}
+
+void CVideoReferenceClock::Stop()
+{
+ CSingleExit lock(g_graphicsContext);
+ StopThread();
+}
+
+void CVideoReferenceClock::CBUpdateClock(int NrVBlanks, uint64_t time)
+{
{
- XCloseDisplay(m_Dpy);
- m_Dpy = NULL;
+ CSingleLock lock(g_VideoReferenceClock.m_CritSection);
+ g_VideoReferenceClock.m_VblankTime = time;
+ g_VideoReferenceClock.UpdateClock(NrVBlanks, true);
}
-#endif
+
+ g_VideoReferenceClock.SendVblankSignal();
}
void CVideoReferenceClock::Process()
@@ -154,33 +87,23 @@ void CVideoReferenceClock::Process()
bool SetupSuccess = false;
int64_t Now;
-#if defined(TARGET_WINDOWS) && defined(HAS_DX)
- //register callback
- m_D3dCallback.Reset();
- g_Windowing.Register(&m_D3dCallback);
-#endif
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- g_Windowing.Register(this);
- m_xrrEvent = false;
-#endif
-
while(!m_bStop)
{
//set up the vblank clock
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- SetupSuccess = SetupGLX();
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- SetupSuccess = SetupD3D();
-#elif defined(TARGET_DARWIN)
- SetupSuccess = SetupCocoa();
-#elif defined(HAS_GLX)
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: compiled without RandR support");
+#if defined(HAS_GLX)
+ m_pVideoSync = new CVideoSyncGLX();
#elif defined(TARGET_WINDOWS)
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: only available on directx build");
-#else
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: no implementation available");
+ m_pVideoSync = new CVideoSyncD3D();
+#elif defined(TARGET_DARWIN)
+ m_pVideoSync = new CVideoSyncCocoa();
#endif
+ if (m_pVideoSync)
+ {
+ SetupSuccess = m_pVideoSync->Setup(CBUpdateClock);
+ UpdateRefreshrate();
+ }
+
CSingleLock SingleLock(m_CritSection);
Now = CurrentHostCounter();
m_CurrTime = Now + m_ClockOffset; //add the clock offset from the previous time we stopped
@@ -190,7 +113,7 @@ void CVideoReferenceClock::Process()
m_TotalMissedVblanks = 0;
m_fineadjust = 1.0;
m_RefreshChanged = 0;
- m_Started.Set();
+ m_MissedVblanks = 0;
if (SetupSuccess)
{
@@ -199,14 +122,7 @@ void CVideoReferenceClock::Process()
SingleLock.Leave();
//run the clock
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- RunGLX();
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- RunD3D();
-#elif defined(TARGET_DARWIN)
- RunCocoa();
-#endif
-
+ m_pVideoSync->Run(m_bStop);
}
else
{
@@ -221,650 +137,14 @@ void CVideoReferenceClock::Process()
SingleLock.Leave();
//clean up the vblank clock
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- CleanupGLX();
- if (m_xrrEvent)
- {
- m_releaseEvent.Set();
- while (!m_bStop)
- {
- if (m_resetEvent.WaitMSec(100))
- break;
- }
- m_xrrEvent = false;
- }
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- CleanupD3D();
-#elif defined(TARGET_DARWIN)
- CleanupCocoa();
-#endif
- if (!SetupSuccess) break;
- }
-
-#if defined(TARGET_WINDOWS) && defined(HAS_DX)
- g_Windowing.Unregister(&m_D3dCallback);
-#endif
-#if defined(HAS_GLX)
- g_Windowing.Unregister(this);
-#endif
-}
-
-bool CVideoReferenceClock::WaitStarted(int MSecs)
-{
- //not waiting here can cause issues with alsa
- return m_Started.WaitMSec(MSecs);
-}
-
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
-
-void CVideoReferenceClock::OnLostDevice()
-{
- if (!m_xrrEvent)
- {
- m_releaseEvent.Reset();
- m_resetEvent.Reset();
- m_xrrEvent = true;
- m_releaseEvent.Wait();
- }
-}
-
-void CVideoReferenceClock::OnResetDevice()
-{
- m_xrrEvent = false;
- m_resetEvent.Set();
-}
-
-bool CVideoReferenceClock::SetupGLX()
-{
- int singleBufferAttributes[] = {
- GLX_RGBA,
- GLX_RED_SIZE, 0,
- GLX_GREEN_SIZE, 0,
- GLX_BLUE_SIZE, 0,
- None
- };
-
- int ReturnV, SwaMask;
- unsigned int GlxTest;
- XSetWindowAttributes Swa;
-
- m_vInfo = NULL;
- m_Context = NULL;
- m_Window = 0;
-
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setting up GLX");
-
- if (!m_Dpy)
- {
- m_Dpy = XOpenDisplay(NULL);
- if (!m_Dpy)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Unable to open display");
- return false;
- }
- }
-
- if (!glXQueryExtension(m_Dpy, NULL, NULL))
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: X server does not support GLX");
- return false;
- }
-
- bool ExtensionFound = false;
- istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen()));
- string ExtensionStr;
-
- while (!ExtensionFound)
- {
- Extensions >> ExtensionStr;
- if (Extensions.fail())
+ m_pVideoSync->Cleanup();
+ delete m_pVideoSync;
+ m_pVideoSync = NULL;
+ if (!SetupSuccess)
break;
-
- if (ExtensionStr == "GLX_SGI_video_sync")
- ExtensionFound = true;
- }
-
- if (!ExtensionFound)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: X server does not support GLX_SGI_video_sync");
- return false;
- }
-
- m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes);
- if (!m_vInfo)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL");
- return false;
- }
-
- Swa.border_pixel = 0;
- Swa.event_mask = StructureNotifyMask;
- Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone );
- SwaMask = CWBorderPixel | CWColormap | CWEventMask;
-
- m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0,
- m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa);
-
- m_Context = glXCreateContext(m_Dpy, m_vInfo, NULL, True);
- if (!m_Context)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXCreateContext returned NULL");
- return false;
- }
-
- ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
- if (ReturnV != True)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
- return false;
- }
-
- m_glXWaitVideoSyncSGI = (int (*)(int, int, unsigned int*))glXGetProcAddress((const GLubyte*)"glXWaitVideoSyncSGI");
- if (!m_glXWaitVideoSyncSGI)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI not found");
- return false;
- }
-
- ReturnV = m_glXWaitVideoSyncSGI(2, 0, &GlxTest);
- if (ReturnV)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI returned %i", ReturnV);
- return false;
- }
-
- m_glXGetVideoSyncSGI = (int (*)(unsigned int*))glXGetProcAddress((const GLubyte*)"glXGetVideoSyncSGI");
- if (!m_glXGetVideoSyncSGI)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXGetVideoSyncSGI not found");
- return false;
- }
-
- ReturnV = m_glXGetVideoSyncSGI(&GlxTest);
- if (ReturnV)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXGetVideoSyncSGI returned %i", ReturnV);
- return false;
- }
-
- XRRSizes(m_Dpy, m_vInfo->screen, &ReturnV);
- if (ReturnV == 0)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: RandR not supported");
- return false;
- }
-
- UpdateRefreshrate(true); //forced refreshrate update
- m_MissedVblanks = 0;
-
- return true;
-}
-
-void CVideoReferenceClock::CleanupGLX()
-{
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Cleaning up GLX");
-
- if (m_vInfo)
- {
- XFree(m_vInfo);
- m_vInfo = NULL;
- }
- if (m_Context)
- {
- glXMakeCurrent(m_Dpy, None, NULL);
- glXDestroyContext(m_Dpy, m_Context);
- m_Context = NULL;
- }
- if (m_Window)
- {
- XDestroyWindow(m_Dpy, m_Window);
- m_Window = 0;
- }
-
- //ati saves the Display* in their libGL, if we close it here, we crash
- if (m_Dpy)
- {
- XCloseDisplay(m_Dpy);
- m_Dpy = NULL;
}
}
-void CVideoReferenceClock::RunGLX()
-{
- unsigned int PrevVblankCount;
- unsigned int VblankCount;
- int ReturnV;
- bool IsReset = false;
- int64_t Now;
-
- CSingleLock SingleLock(m_CritSection);
- SingleLock.Leave();
-
- //get the current vblank counter
- m_glXGetVideoSyncSGI(&VblankCount);
- PrevVblankCount = VblankCount;
-
- while(!m_bStop)
- {
- if (m_xrrEvent)
- return;
-
- //wait for the next vblank
- ReturnV = m_glXWaitVideoSyncSGI(2, (VblankCount + 1) % 2, &VblankCount);
- m_glXGetVideoSyncSGI(&VblankCount); //the vblank count returned by glXWaitVideoSyncSGI is not always correct
- Now = CurrentHostCounter(); //get the timestamp of this vblank
-
- if(ReturnV)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI returned %i", ReturnV);
- return;
- }
-
- if (VblankCount > PrevVblankCount)
- {
- //update the vblank timestamp, update the clock and send a signal that we got a vblank
- SingleLock.Enter();
- m_VblankTime = Now;
- UpdateClock((int)(VblankCount - PrevVblankCount), true);
- SingleLock.Leave();
- SendVblankSignal();
- IsReset = false;
- }
- else
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Vblank counter has reset");
-
- //only try reattaching once
- if (IsReset)
- return;
-
- //because of a bug in the nvidia driver, glXWaitVideoSyncSGI breaks when the vblank counter resets
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detaching glX context");
- ReturnV = glXMakeCurrent(m_Dpy, None, NULL);
- if (ReturnV != True)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
- return;
- }
-
- //sleep here so we don't busy spin when this constantly happens, for example when the display went to sleep
- Sleep(1000);
-
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Attaching glX context");
- ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
- if (ReturnV != True)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
- return;
- }
-
- m_glXGetVideoSyncSGI(&VblankCount);
-
- IsReset = true;
- }
- PrevVblankCount = VblankCount;
- }
-}
-
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
-
-void CVideoReferenceClock::RunD3D()
-{
- D3DRASTER_STATUS RasterStatus;
- int64_t Now;
- int64_t LastVBlankTime;
- unsigned int LastLine;
- int NrVBlanks;
- double VBlankTime;
- int ReturnV;
-
- CSingleLock SingleLock(m_CritSection);
- SingleLock.Leave();
-
- //get the scanline we're currently at
- m_D3dDev->GetRasterStatus(0, &RasterStatus);
- if (RasterStatus.InVBlank) LastLine = 0;
- else LastLine = RasterStatus.ScanLine;
-
- //init the vblanktime
- Now = CurrentHostCounter();
- LastVBlankTime = Now;
-
- while(!m_bStop && m_D3dCallback.IsValid())
- {
- //get the scanline we're currently at
- ReturnV = m_D3dDev->GetRasterStatus(0, &RasterStatus);
- if (ReturnV != D3D_OK)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GetRasterStatus returned returned %s: %s",
- DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
- return;
- }
-
- //if InVBlank is set, or the current scanline is lower than the previous scanline, a vblank happened
- if ((RasterStatus.InVBlank && LastLine > 0) || (RasterStatus.ScanLine < LastLine))
- {
- //calculate how many vblanks happened
- Now = CurrentHostCounter() - m_SystemFrequency * RasterStatus.ScanLine / (m_Height * MathUtils::round_int(m_RefreshRate));
- VBlankTime = (double)(Now - LastVBlankTime) / (double)m_SystemFrequency;
- NrVBlanks = MathUtils::round_int(VBlankTime * m_RefreshRate);
-
- //update the vblank timestamp, update the clock and send a signal that we got a vblank
- SingleLock.Enter();
- m_VblankTime = Now;
- UpdateClock(NrVBlanks, true);
- SingleLock.Leave();
- SendVblankSignal();
-
- if (UpdateRefreshrate())
- {
- //we have to measure the refreshrate again
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Displaymode changed");
- return;
- }
-
- //save the timestamp of this vblank so we can calculate how many vblanks happened next time
- LastVBlankTime = Now;
-
- //because we had a vblank, sleep until half the refreshrate period
- Now = CurrentHostCounter();
- int SleepTime = (int)((LastVBlankTime + (m_SystemFrequency / MathUtils::round_int(m_RefreshRate) / 2) - Now) * 1000 / m_SystemFrequency);
- if (SleepTime > 100) SleepTime = 100; //failsafe
- if (SleepTime > 0) ::Sleep(SleepTime);
- }
- else
- {
- ::Sleep(1);
- }
-
- if (RasterStatus.InVBlank) LastLine = 0;
- else LastLine = RasterStatus.ScanLine;
- }
-}
-
-//how many times we measure the refreshrate
-#define NRMEASURES 6
-//how long to measure in milliseconds
-#define MEASURETIME 250
-
-bool CVideoReferenceClock::SetupD3D()
-{
- int ReturnV;
-
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setting up Direct3d");
-
- m_D3dCallback.Aquire();
-
- //get d3d device
- m_D3dDev = g_Windowing.Get3DDevice();
-
- //we need a high priority thread to get accurate timing
- if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: SetThreadPriority failed");
-
- D3DCAPS9 DevCaps;
- ReturnV = m_D3dDev->GetDeviceCaps(&DevCaps);
- if (ReturnV != D3D_OK)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GetDeviceCaps returned %s: %s",
- DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
- return false;
- }
-
- if ((DevCaps.Caps & D3DCAPS_READ_SCANLINE) != D3DCAPS_READ_SCANLINE)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Hardware does not support GetRasterStatus");
- return false;
- }
-
- D3DRASTER_STATUS RasterStatus;
- ReturnV = m_D3dDev->GetRasterStatus(0, &RasterStatus);
- if (ReturnV != D3D_OK)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GetRasterStatus returned returned %s: %s",
- DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
- return false;
- }
-
- D3DDISPLAYMODE DisplayMode;
- ReturnV = m_D3dDev->GetDisplayMode(0, &DisplayMode);
- if (ReturnV != D3D_OK)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GetDisplayMode returned returned %s: %s",
- DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
- return false;
- }
-
- //forced update of windows refreshrate
- UpdateRefreshrate(true);
-
- if (g_advancedSettings.m_measureRefreshrate)
- {
- //measure the refreshrate a couple times
- list<double> Measures;
- for (int i = 0; i < NRMEASURES; i++)
- Measures.push_back(MeasureRefreshrate(MEASURETIME));
-
- //build up a string of measured rates
- CStdString StrRates;
- for (list<double>::iterator it = Measures.begin(); it != Measures.end(); it++)
- StrRates += StringUtils::Format("%.2f ", *it);
-
- //get the top half of the measured rates
- Measures.sort();
- double RefreshRate = 0.0;
- int NrMeasurements = 0;
- while (NrMeasurements < NRMEASURES / 2 && !Measures.empty())
- {
- if (Measures.back() > 0.0)
- {
- RefreshRate += Measures.back();
- NrMeasurements++;
- }
- Measures.pop_back();
- }
-
- if (NrMeasurements < NRMEASURES / 2)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: refreshrate measurements: %s, unable to get a good measurement",
- StrRates.c_str(), m_RefreshRate);
- return false;
- }
-
- RefreshRate /= NrMeasurements;
- m_RefreshRate = RefreshRate;
-
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: refreshrate measurements: %s, assuming %i hertz", StrRates.c_str(), m_RefreshRate);
- }
- else
- {
- m_RefreshRate = m_PrevRefreshRate;
- if (MathUtils::round_int(m_RefreshRate) == 23 ||
- MathUtils::round_int(m_RefreshRate) == 29 ||
- MathUtils::round_int(m_RefreshRate) == 59)
- m_RefreshRate++;
-
- if (m_Interlaced)
- {
- m_RefreshRate *= 2;
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: display is interlaced");
- }
-
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: detected refreshrate: %i hertz, assuming %i hertz", m_PrevRefreshRate, MathUtils::round_int(m_RefreshRate));
- }
-
- m_MissedVblanks = 0;
-
- return true;
-}
-
-double CVideoReferenceClock::MeasureRefreshrate(int MSecs)
-{
- D3DRASTER_STATUS RasterStatus;
- int64_t Now;
- int64_t Target;
- int64_t Prev;
- int64_t AvgInterval;
- int64_t MeasureCount;
- unsigned int LastLine;
- int ReturnV;
-
- Now = CurrentHostCounter();
- Target = Now + (m_SystemFrequency * MSecs / 1000);
- Prev = -1;
- AvgInterval = 0;
- MeasureCount = 0;
-
- //start measuring vblanks
- LastLine = 0;
- while(Now <= Target)
- {
- ReturnV = m_D3dDev->GetRasterStatus(0, &RasterStatus);
- Now = CurrentHostCounter();
- if (ReturnV != D3D_OK)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GetRasterStatus returned returned %s: %s",
- DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
- return -1.0;
- }
-
- if ((RasterStatus.InVBlank && LastLine != 0) || (!RasterStatus.InVBlank && RasterStatus.ScanLine < LastLine))
- { //we got a vblank
- if (Prev != -1) //need two for a measurement
- {
- AvgInterval += Now - Prev; //save how long this vblank lasted
- MeasureCount++;
- }
- Prev = Now; //save this time for the next measurement
- }
-
- //save the current scanline
- if (RasterStatus.InVBlank)
- LastLine = 0;
- else
- LastLine = RasterStatus.ScanLine;
-
- ::Sleep(1);
- }
-
- if (MeasureCount < 1)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Didn't measure any vblanks");
- return -1.0;
- }
-
- double fRefreshRate = 1.0 / ((double)AvgInterval / (double)MeasureCount / (double)m_SystemFrequency);
-
- return fRefreshRate;
-}
-
-void CVideoReferenceClock::CleanupD3D()
-{
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Cleaning up Direct3d");
- m_D3dCallback.Release();
-}
-
-#elif defined(TARGET_DARWIN)
-#if defined(TARGET_DARWIN_OSX)
-// 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)
-{
- double fps = 60.0;
-
- if (inNow->videoRefreshPeriod > 0)
- fps = (double)inOutputTime->videoTimeScale / (double)inOutputTime->videoRefreshPeriod;
-
- // Create an autorelease pool (necessary to call into non-Obj-C code from Obj-C code)
- void* pool = Cocoa_Create_AutoReleasePool();
-
- CVideoReferenceClock *VideoReferenceClock = reinterpret_cast<CVideoReferenceClock*>(displayLinkContext);
- VideoReferenceClock->VblankHandler(inOutputTime->hostTime, fps);
-
- // Destroy the autorelease pool
- Cocoa_Destroy_AutoReleasePool(pool);
-
- return kCVReturnSuccess;
-}
-#endif
-bool CVideoReferenceClock::SetupCocoa()
-{
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: setting up Cocoa");
-
- //init the vblank timestamp
- m_LastVBlankTime = CurrentHostCounter();
- m_MissedVblanks = 0;
- m_RefreshRate = 60; //init the refreshrate so we don't get any division by 0 errors
-
- #if defined(TARGET_DARWIN_IOS)
- {
- g_Windowing.InitDisplayLink();
- }
- #else
- if (!Cocoa_CVDisplayLinkCreate((void*)DisplayLinkCallBack, reinterpret_cast<void*>(this)))
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Cocoa_CVDisplayLinkCreate failed");
- return false;
- }
- else
- #endif
- {
- UpdateRefreshrate(true);
- return true;
- }
-}
-
-void CVideoReferenceClock::RunCocoa()
-{
- //because cocoa has a vblank callback, we just keep sleeping until we're asked to stop the thread
- while(!m_bStop)
- {
- Sleep(1000);
- }
-}
-
-void CVideoReferenceClock::CleanupCocoa()
-{
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: cleaning up Cocoa");
- #if defined(TARGET_DARWIN_IOS)
- g_Windowing.DeinitDisplayLink();
- #else
- Cocoa_CVDisplayLinkRelease();
- #endif
-}
-
-void CVideoReferenceClock::VblankHandler(int64_t nowtime, double fps)
-{
- int NrVBlanks;
- double VBlankTime;
- int RefreshRate = MathUtils::round_int(fps);
-
- CSingleLock SingleLock(m_CritSection);
-
- if (RefreshRate != MathUtils::round_int(m_RefreshRate))
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %f hertz, rounding to %i hertz", fps, RefreshRate);
- m_RefreshRate = RefreshRate;
- }
- m_LastRefreshTime = m_CurrTime;
-
- //calculate how many vblanks happened
- VBlankTime = (double)(nowtime - m_LastVBlankTime) / (double)m_SystemFrequency;
- NrVBlanks = MathUtils::round_int(VBlankTime * m_RefreshRate);
-
- //save the timestamp of this vblank so we can calculate how many happened next time
- m_LastVBlankTime = nowtime;
-
- //update the vblank timestamp, update the clock and send a signal that we got a vblank
- m_VblankTime = nowtime;
- UpdateClock(NrVBlanks, true);
-
- SingleLock.Leave();
-
- SendVblankSignal();
- UpdateRefreshrate();
-}
-#endif
-
//this is called from the vblank run function and from CVideoReferenceClock::Wait in case of a late update
void CVideoReferenceClock::UpdateClock(int NrVBlanks, bool CheckMissed)
{
@@ -979,79 +259,12 @@ double CVideoReferenceClock::GetSpeed()
return 1.0;
}
-bool CVideoReferenceClock::UpdateRefreshrate(bool Forced /*= false*/)
+void CVideoReferenceClock::UpdateRefreshrate()
{
- //if the graphicscontext signaled that the refreshrate changed, we check it about one second later
- if (m_RefreshChanged == 1 && !Forced)
- {
- m_LastRefreshTime = m_CurrTime;
- m_RefreshChanged = 2;
- return false;
- }
-
- //update the refreshrate about once a second, or update immediately if a forced update is required
- if (m_CurrTime - m_LastRefreshTime < m_SystemFrequency && !Forced)
- return false;
-
- if (Forced)
- m_LastRefreshTime = 0;
- else
- m_LastRefreshTime = m_CurrTime;
-
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
-
- if (!Forced)
- m_RefreshChanged = 0;
-
- if (!Forced) //refreshrate did not change
- return false;
-
CSingleLock SingleLock(m_CritSection);
- m_RefreshRate = g_graphicsContext.GetFPS();
+ m_RefreshRate = m_pVideoSync->GetFps();
CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %.3f hertz", m_RefreshRate);
-
- return true;
-
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
-
- D3DDISPLAYMODE DisplayMode;
- m_D3dDev->GetDisplayMode(0, &DisplayMode);
-
- //0 indicates adapter default
- if (DisplayMode.RefreshRate == 0)
- DisplayMode.RefreshRate = 60;
-
- if (m_PrevRefreshRate != DisplayMode.RefreshRate || m_Width != DisplayMode.Width || m_Height != DisplayMode.Height ||
- m_Interlaced != g_Windowing.Interlaced() || Forced )
- {
- m_PrevRefreshRate = DisplayMode.RefreshRate;
- m_Width = DisplayMode.Width;
- m_Height = DisplayMode.Height;
- m_Interlaced = g_Windowing.Interlaced();
- return true;
- }
-
- return false;
-
-#elif defined(TARGET_DARWIN)
- #if defined(TARGET_DARWIN_IOS)
- int RefreshRate = round(g_Windowing.GetDisplayLinkFPS() + 0.5);
- #else
- int RefreshRate = MathUtils::round_int(Cocoa_GetCVDisplayLinkRefreshPeriod());
- #endif
-
- if (RefreshRate != MathUtils::round_int(m_RefreshRate) || Forced)
- {
- CSingleLock SingleLock(m_CritSection);
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detected refreshrate: %i hertz", RefreshRate);
- m_RefreshRate = RefreshRate;
- return true;
- }
- return false;
-#endif
-
- return false;
}
//dvdplayer needs to know the refreshrate for matching the fps of the video playing to it
diff --git a/xbmc/video/VideoReferenceClock.h b/xbmc/video/VideoReferenceClock.h
index 6027031449..33a0adf568 100644
--- a/xbmc/video/VideoReferenceClock.h
+++ b/xbmc/video/VideoReferenceClock.h
@@ -19,47 +19,12 @@
*
*/
-#include "system.h" // for HAS_XRANDR, and Win32 types
#include "threads/Thread.h"
#include "threads/CriticalSection.h"
-//TODO: get rid of #ifdef hell, abstract implementations in separate classes
-
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- #include "system_gl.h"
- #include <X11/X.h>
- #include <X11/Xlib.h>
- #include <GL/glx.h>
- #include "guilib/DispResource.h"
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- #include <d3d9.h>
- #include "guilib/D3DResource.h"
-
-class CD3DCallback : public ID3DResource
-{
- public:
- void Reset();
- void OnDestroyDevice();
- void OnCreateDevice();
- void Aquire();
- void Release();
- bool IsValid();
-
- private:
- bool m_devicevalid;
- bool m_deviceused;
-
- CCriticalSection m_critsection;
- CEvent m_createevent;
- CEvent m_releaseevent;
-};
-
-#endif
+class CVideoSync;
class CVideoReferenceClock : public CThread
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- ,public IDispResource
-#endif
{
public:
CVideoReferenceClock();
@@ -71,86 +36,40 @@ class CVideoReferenceClock : public CThread
double GetSpeed();
double GetRefreshRate(double* interval = NULL);
int64_t Wait(int64_t Target);
- bool WaitStarted(int MSecs);
bool GetClockInfo(int& MissedVblanks, double& ClockSpeed, double& RefreshRate);
void SetFineAdjust(double fineadjust);
void RefreshChanged() { m_RefreshChanged = 1; }
-
-#if defined(TARGET_DARWIN)
- void VblankHandler(int64_t nowtime, double fps);
-#endif
-
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- virtual void OnLostDevice();
- virtual void OnResetDevice();
-#endif
+ void Stop();
private:
void Process();
- bool UpdateRefreshrate(bool Forced = false);
+ void UpdateRefreshrate();
void SendVblankSignal();
void UpdateClock(int NrVBlanks, bool CheckMissed);
double UpdateInterval();
int64_t TimeOfNextVblank();
+ static void CBUpdateClock(int NrVBlanks, uint64_t time);
int64_t m_CurrTime; //the current time of the clock when using vblank as clock source
int64_t m_LastIntTime; //last interpolated clock value, to make sure the clock doesn't go backwards
double m_CurrTimeFract; //fractional part that is lost due to rounding when updating the clock
double m_ClockSpeed; //the frequency of the clock set by dvdplayer
int64_t m_ClockOffset; //the difference between the vblank clock and systemclock, set when vblank clock is stopped
- int64_t m_LastRefreshTime; //last time we updated the refreshrate
int64_t m_SystemFrequency; //frequency of the systemclock
double m_fineadjust;
bool m_UseVblank; //set to true when vblank is used as clock source
double m_RefreshRate; //current refreshrate
- int m_PrevRefreshRate; //previous refreshrate, used for log printing and getting refreshrate from nvidia-settings
int m_MissedVblanks; //number of clock updates missed by the vblank clock
int m_RefreshChanged; //1 = we changed the refreshrate, 2 = we should check the refreshrate forced
int m_TotalMissedVblanks;//total number of clock updates missed, used by codec information screen
int64_t m_VblankTime; //last time the clock was updated when using vblank as clock
- CEvent m_Started; //set when the vblank clock is started
CEvent m_VblankEvent; //set when a vblank happens
CCriticalSection m_CritSection;
-#if defined(HAS_GLX) && defined(HAS_XRANDR)
- bool SetupGLX();
- void RunGLX();
- void CleanupGLX();
-
- int (*m_glXWaitVideoSyncSGI) (int, int, unsigned int*);
- int (*m_glXGetVideoSyncSGI) (unsigned int*);
-
- Display* m_Dpy;
- XVisualInfo *m_vInfo;
- Window m_Window;
- GLXContext m_Context;
- bool m_xrrEvent;
- CEvent m_releaseEvent, m_resetEvent;
-
-#elif defined(TARGET_WINDOWS) && defined(HAS_DX)
- bool SetupD3D();
- double MeasureRefreshrate(int MSecs);
- void RunD3D();
- void CleanupD3D();
-
- LPDIRECT3DDEVICE9 m_D3dDev;
- CD3DCallback m_D3dCallback;
-
- unsigned int m_Width;
- unsigned int m_Height;
- bool m_Interlaced;
-
-#elif defined(TARGET_DARWIN)
- bool SetupCocoa();
- void RunCocoa();
- void CleanupCocoa();
-
- int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened
- //not the same as m_VblankTime
-#endif
+ CVideoSync *m_pVideoSync;
};
extern CVideoReferenceClock g_VideoReferenceClock;
diff --git a/xbmc/video/videosync/Makefile b/xbmc/video/videosync/Makefile
new file mode 100644
index 0000000000..ce748403f8
--- /dev/null
+++ b/xbmc/video/videosync/Makefile
@@ -0,0 +1,7 @@
+SRCS=VideoSyncGLX.cpp \
+ VideoSyncCocoa.cpp \
+
+LIB=videosync.a
+
+include ../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS))) \ No newline at end of file
diff --git a/xbmc/video/videosync/VideoSync.h b/xbmc/video/videosync/VideoSync.h
new file mode 100644
index 0000000000..0b03f7dcbc
--- /dev/null
+++ b/xbmc/video/videosync/VideoSync.h
@@ -0,0 +1,35 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+typedef void (*PUPDATECLOCK)(int NrVBlanks, uint64_t time);
+
+class CVideoSync
+{
+public:
+ virtual ~CVideoSync() {};
+ virtual bool Setup(PUPDATECLOCK func) = 0;
+ virtual void Run(volatile bool& stop) = 0;
+ virtual void Cleanup() = 0;
+ virtual float GetFps() = 0;
+protected:
+ PUPDATECLOCK UpdateClock;
+ float m_fps;
+};
diff --git a/xbmc/video/videosync/VideoSyncCocoa.cpp b/xbmc/video/videosync/VideoSyncCocoa.cpp
new file mode 100644
index 0000000000..1e28183c5a
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncCocoa.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#if defined(TARGET_DARWIN)
+#include "utils/log.h"
+#include "VideoSyncCocoa.h"
+#include "utils/MathUtils.h"
+#include "video/VideoReferenceClock.h"
+#include "utils/TimeUtils.h"
+
+//ios specifics
+#if defined(TARGET_DARWIN_IOS)
+#include "windowing/WindowingFactory.h"
+#endif
+
+//osx specifics
+#if defined(TARGET_DARWIN_OSX)
+#include <QuartzCore/CVDisplayLink.h>
+#include "osx/CocoaInterface.h"
+// 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)
+{
+ double fps = 60.0;
+
+ if (inNow->videoRefreshPeriod > 0)
+ fps = (double)inOutputTime->videoTimeScale / (double)inOutputTime->videoRefreshPeriod;
+
+ // Create an autorelease pool (necessary to call into non-Obj-C code from Obj-C code)
+ void* pool = Cocoa_Create_AutoReleasePool();
+
+ CVideoSyncCocoa *VideoSyncCocoa = reinterpret_cast<CVideoSyncCocoa*>(displayLinkContext);
+ VideoSyncCocoa->VblankHandler(inOutputTime->hostTime, fps);
+
+ // Destroy the autorelease pool
+ Cocoa_Destroy_AutoReleasePool(pool);
+
+ return kCVReturnSuccess;
+}
+#endif
+
+void CVideoSyncCocoa::VblankHandler(int64_t nowtime, double fps)
+{
+ int NrVBlanks;
+ double VBlankTime;
+ int RefreshRate = MathUtils::round_int(fps);
+
+ if (RefreshRate != MathUtils::round_int(m_fps))
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncCocoa: Detected refreshrate: %f hertz, rounding to %i hertz", fps, RefreshRate);
+ UpdateFPS(fps);
+ }
+
+ //calculate how many vblanks happened
+ VBlankTime = (double)(nowtime - m_LastVBlankTime) / (double)g_VideoReferenceClock.GetFrequency();
+ NrVBlanks = MathUtils::round_int(VBlankTime * m_fps);
+
+ //save the timestamp of this vblank so we can calculate how many happened next time
+ m_LastVBlankTime = nowtime;
+
+ //update the vblank timestamp, update the clock and send a signal that we got a vblank
+ UpdateClock(NrVBlanks, nowtime);
+}
+
+bool CVideoSyncCocoa::Setup(PUPDATECLOCK func)
+{
+ CLog::Log(LOGDEBUG, "CVideoSyncCocoa: setting up Cocoa");
+
+ //init the vblank timestamp
+ m_LastVBlankTime = CurrentHostCounter();
+ UpdateClock = func;
+
+#if defined(TARGET_DARWIN_IOS)
+ {
+ g_Windowing.InitDisplayLink(this);
+ }
+#else
+ if (!Cocoa_CVDisplayLinkCreate((void*)DisplayLinkCallBack, reinterpret_cast<void*>(this)))
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncCocoa: Cocoa_CVDisplayLinkCreate failed");
+ return false;
+ }
+ else
+#endif
+ {
+ GetFps();//UpdateRefreshrate(true); - FIXME?NEEDED?
+ return true;
+ }
+}
+
+void CVideoSyncCocoa::Run(volatile bool& stop)
+{
+ //because cocoa has a vblank callback, we just keep sleeping until we're asked to stop the thread
+ while(!stop)
+ {
+ Sleep(1000);
+ }
+}
+
+void CVideoSyncCocoa::Cleanup()
+{
+ CLog::Log(LOGDEBUG, "CVideoSyncCocoa: cleaning up Cocoa");
+#if defined(TARGET_DARWIN_IOS)
+ g_Windowing.DeinitDisplayLink();
+#else
+ Cocoa_CVDisplayLinkRelease();
+#endif
+}
+
+void CVideoSyncCocoa::UpdateFPS(double fps)
+{
+ int fpsInt = MathUtils::round_int(fps);
+
+ if (fpsInt != MathUtils::round_int(m_fps))
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncCocoa: Detected refreshrate: %i hertz", fpsInt);
+ m_fps = fpsInt;
+ }
+}
+
+float CVideoSyncCocoa::GetFps()
+{
+#if defined(TARGET_DARWIN_IOS)
+ UpdateFPS(g_Windowing.GetDisplayLinkFPS() + 0.5);
+#else
+ UpdateFPS(Cocoa_GetCVDisplayLinkRefreshPeriod());
+#endif
+
+ return m_fps;
+}
+
+#endif//TARGET_DARWIN
diff --git a/xbmc/video/videosync/VideoSyncCocoa.h b/xbmc/video/videosync/VideoSyncCocoa.h
new file mode 100644
index 0000000000..a7ddc73e56
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncCocoa.h
@@ -0,0 +1,37 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(TARGET_DARWIN)
+#include "VideoSync.h"
+class CVideoSyncCocoa : public CVideoSync
+{
+public:
+ virtual bool Setup(PUPDATECLOCK func);
+ virtual void Run(volatile bool& stop);
+ virtual void Cleanup();
+ virtual float GetFps();
+ void VblankHandler(int64_t nowtime, double fps);
+private:
+ void UpdateFPS(double fps);
+ int64_t m_LastVBlankTime; //timestamp of the last vblank, used for calculating how many vblanks happened
+};
+
+#endif
diff --git a/xbmc/video/videosync/VideoSyncD3D.cpp b/xbmc/video/videosync/VideoSyncD3D.cpp
new file mode 100644
index 0000000000..166635f724
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncD3D.cpp
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#if defined(TARGET_WINDOWS)
+
+#pragma comment (lib,"d3d9.lib")
+#pragma comment (lib,"DxErr.lib")
+#include <Dxerr.h>
+#include "utils/log.h"
+#include "Utils/TimeUtils.h"
+#include "Utils/MathUtils.h"
+#include "windowing\WindowingFactory.h"
+#include "video/videosync/VideoSyncD3D.h"
+#include "guilib/GraphicContext.h"
+
+void CVideoSyncD3D::OnDestroyDevice()
+{
+ if (!m_displayLost)
+ {
+ m_displayLost = true;
+ m_lostEvent.Wait();
+ }
+}
+
+void CVideoSyncD3D::OnResetDevice()
+{
+ m_displayReset = true;
+}
+
+bool CVideoSyncD3D::Setup(PUPDATECLOCK func)
+{
+ int ReturnV;
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: Setting up Direct3d");
+ CSingleLock lock(g_graphicsContext);
+ g_Windowing.Register(this);
+ m_displayLost = false;
+ m_displayReset = false;
+ m_lostEvent.Reset();
+ UpdateClock = func;
+
+ //get d3d device
+ m_D3dDev = g_Windowing.Get3DDevice();
+ //we need a high priority thread to get accurate timing
+ if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: SetThreadPriority failed");
+
+ D3DCAPS9 DevCaps;
+ ReturnV = m_D3dDev->GetDeviceCaps(&DevCaps);
+
+ if (ReturnV != D3D_OK)
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: GetDeviceCaps returned %s: %s",
+ DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
+ return false;
+ }
+
+ if ((DevCaps.Caps & D3DCAPS_READ_SCANLINE) != D3DCAPS_READ_SCANLINE)
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: Hardware does not support GetRasterStatus");
+ return false;
+ }
+
+ D3DRASTER_STATUS RasterStatus;
+ ReturnV = m_D3dDev->GetRasterStatus(0, &RasterStatus);
+ if (ReturnV != D3D_OK)
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: GetRasterStatus returned returned %s: %s",
+ DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
+ return false;
+ }
+
+ D3DDISPLAYMODE DisplayMode;
+ ReturnV = m_D3dDev->GetDisplayMode(0, &DisplayMode);
+ if (ReturnV != D3D_OK)
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: GetDisplayMode returned returned %s: %s",
+ DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
+ return false;
+ }
+ m_height = DisplayMode.Height;
+
+ return true;
+}
+
+void CVideoSyncD3D::Run(volatile bool& stop)
+{
+ D3DRASTER_STATUS RasterStatus;
+ int64_t Now;
+ int64_t LastVBlankTime;
+ unsigned int LastLine;
+ int NrVBlanks;
+ double VBlankTime;
+ int ReturnV;
+ int64_t systemFrequency = CurrentHostFrequency();
+
+ //get the scanline we're currently at
+ m_D3dDev->GetRasterStatus(0, &RasterStatus);
+ if (RasterStatus.InVBlank)
+ LastLine = 0;
+ else
+ LastLine = RasterStatus.ScanLine;
+
+ //init the vblanktime
+ Now = CurrentHostCounter();
+ LastVBlankTime = Now;
+ m_lastUpdateTime = Now - systemFrequency;
+ while (!stop && !m_displayLost && !m_displayReset)
+ {
+ //get the scanline we're currently at
+ ReturnV = m_D3dDev->GetRasterStatus(0, &RasterStatus);
+ if (ReturnV != D3D_OK)
+ {
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: GetRasterStatus returned returned %s: %s",
+ DXGetErrorString(ReturnV), DXGetErrorDescription(ReturnV));
+ return;
+ }
+
+ //if InVBlank is set, or the current scanline is lower than the previous scanline, a vblank happened
+ if ((RasterStatus.InVBlank && LastLine > 0) || (RasterStatus.ScanLine < LastLine))
+ {
+ //calculate how many vblanks happened
+ Now = CurrentHostCounter() - systemFrequency * RasterStatus.ScanLine / (m_height * MathUtils::round_int(m_fps));
+ VBlankTime = (double)(Now - LastVBlankTime) / (double)systemFrequency;
+ NrVBlanks = MathUtils::round_int(VBlankTime * m_fps);
+ //update the vblank timestamp, update the clock and send a signal that we got a vblank
+ UpdateClock(NrVBlanks, Now);
+
+ //save the timestamp of this vblank so we can calculate how many vblanks happened next time
+ LastVBlankTime = Now;
+ //because we had a vblank, sleep until half the refreshrate period
+ Now = CurrentHostCounter();
+
+ if ((Now - m_lastUpdateTime) >= systemFrequency)
+ {
+ if (m_fps != GetFps())
+ break;
+ }
+
+ int SleepTime = (int)((LastVBlankTime + (systemFrequency / MathUtils::round_int(m_fps) / 2) - Now) * 1000 / systemFrequency);
+ if (SleepTime > 100)
+ SleepTime = 100; //failsafe
+ if (SleepTime > 0)
+ ::Sleep(SleepTime);
+ }
+ else
+ {
+ ::Sleep(1);
+ }
+
+ if (RasterStatus.InVBlank)
+ LastLine = 0;
+ else
+ LastLine = RasterStatus.ScanLine;
+ }
+
+ m_lostEvent.Set();
+ while (!stop && m_displayLost && !m_displayReset)
+ {
+ Sleep(10);
+ }
+}
+
+void CVideoSyncD3D::Cleanup()
+{
+ CLog::Log(LOGDEBUG, "CVideoSyncD3D: Cleaning up Direct3d");
+ CSingleLock lock(g_graphicsContext);
+
+ m_lostEvent.Set();
+ g_Windowing.Unregister(this);
+}
+
+float CVideoSyncD3D::GetFps()
+{
+ D3DDISPLAYMODE DisplayMode;
+ m_D3dDev->GetDisplayMode(0, &DisplayMode);
+ m_fps = DisplayMode.RefreshRate;
+ if (m_fps == 0)
+ m_fps = 60;
+
+ if (m_fps == 23 || m_fps == 29 || m_fps == 59)
+ m_fps++;
+
+ if (g_Windowing.Interlaced())
+ {
+ m_fps *= 2;
+ }
+ return m_fps;
+}
+#endif
diff --git a/xbmc/video/videosync/VideoSyncD3D.h b/xbmc/video/videosync/VideoSyncD3D.h
new file mode 100644
index 0000000000..5ccbdd24f9
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncD3D.h
@@ -0,0 +1,50 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(TARGET_WINDOWS)
+
+#include "video/videosync/VideoSync.h"
+#include <d3d9.h>
+#include "guilib/D3DResource.h"
+#include "threads/CriticalSection.h"
+#include "threads/Event.h"
+
+class CVideoSyncD3D : public CVideoSync, ID3DResource
+{
+public:
+ virtual bool Setup(PUPDATECLOCK func);
+ virtual void Run(volatile bool& stop);
+ virtual void Cleanup();
+ virtual float GetFps();
+
+ virtual void OnCreateDevice() {}
+ virtual void OnDestroyDevice();
+ virtual void OnResetDevice();
+private:
+ LPDIRECT3DDEVICE9 m_D3dDev;
+ int m_height;
+ volatile bool m_displayLost;
+ volatile bool m_displayReset;
+ CEvent m_lostEvent;
+ int64_t m_lastUpdateTime;
+};
+
+#endif
diff --git a/xbmc/video/videosync/VideoSyncGLX.cpp b/xbmc/video/videosync/VideoSyncGLX.cpp
new file mode 100644
index 0000000000..fe839045d3
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncGLX.cpp
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "system.h"
+
+#if defined(HAS_GLX)
+
+#include "video/videosync/VideoSyncGLX.h"
+#include <sstream>
+#include <X11/extensions/Xrandr.h>
+#include "windowing/WindowingFactory.h"
+#include "guilib/GraphicContext.h"
+#include "threads/SingleLock.h"
+#include "utils/log.h"
+#include "utils/TimeUtils.h"
+#include <string>
+
+using namespace std;
+
+Display* CVideoSyncGLX::m_Dpy = NULL;
+
+void CVideoSyncGLX::OnLostDevice()
+{
+ if (!m_displayLost)
+ {
+ m_displayLost = true;
+ m_lostEvent.Wait();
+ }
+}
+
+void CVideoSyncGLX::OnResetDevice()
+{
+ m_displayReset = true;
+}
+
+bool CVideoSyncGLX::Setup(PUPDATECLOCK func)
+{
+ CSingleLock lock(g_graphicsContext);
+
+ m_glXWaitVideoSyncSGI = NULL;
+ m_glXGetVideoSyncSGI = NULL;
+ m_vInfo = NULL;
+ m_Window = 0;
+ m_Context = NULL;
+ UpdateClock = func;
+
+ int singleBufferAttributes[] = {
+ GLX_RGBA,
+ GLX_RED_SIZE, 0,
+ GLX_GREEN_SIZE, 0,
+ GLX_BLUE_SIZE, 0,
+ None
+ };
+
+ int ReturnV, SwaMask;
+ unsigned int GlxTest;
+ XSetWindowAttributes Swa;
+
+ m_vInfo = NULL;
+ m_Context = NULL;
+ m_Window = 0;
+
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setting up GLX");
+
+ g_Windowing.Register(this);
+
+ m_displayLost = false;
+ m_displayReset = false;
+ m_lostEvent.Reset();
+
+ if (!m_Dpy)
+ {
+ m_Dpy = XOpenDisplay(NULL);
+ if (!m_Dpy)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Unable to open display");
+ return false;
+ }
+ }
+
+ if (!glXQueryExtension(m_Dpy, NULL, NULL))
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: X server does not support GLX");
+ return false;
+ }
+
+ bool ExtensionFound = false;
+ istringstream Extensions(glXQueryExtensionsString(m_Dpy, g_Windowing.GetCurrentScreen()));
+ string ExtensionStr;
+
+ while (!ExtensionFound)
+ {
+ Extensions >> ExtensionStr;
+ if (Extensions.fail())
+ break;
+
+ if (ExtensionStr == "GLX_SGI_video_sync")
+ ExtensionFound = true;
+ }
+
+ if (!ExtensionFound)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: X server does not support GLX_SGI_video_sync");
+ return false;
+ }
+
+ m_vInfo = glXChooseVisual(m_Dpy, g_Windowing.GetCurrentScreen(), singleBufferAttributes);
+ if (!m_vInfo)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXChooseVisual returned NULL");
+ return false;
+ }
+
+ Swa.border_pixel = 0;
+ Swa.event_mask = StructureNotifyMask;
+ Swa.colormap = XCreateColormap(m_Dpy, g_Windowing.GetWindow(), m_vInfo->visual, AllocNone );
+ SwaMask = CWBorderPixel | CWColormap | CWEventMask;
+
+ m_Window = XCreateWindow(m_Dpy, g_Windowing.GetWindow(), 0, 0, 256, 256, 0,
+ m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa);
+
+ m_Context = glXCreateContext(m_Dpy, m_vInfo, NULL, True);
+ if (!m_Context)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXCreateContext returned NULL");
+ return false;
+ }
+
+ ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ if (ReturnV != True)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
+ return false;
+ }
+
+ m_glXWaitVideoSyncSGI = (int (*)(int, int, unsigned int*))glXGetProcAddress((const GLubyte*)"glXWaitVideoSyncSGI");
+ if (!m_glXWaitVideoSyncSGI)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI not found");
+ return false;
+ }
+
+ ReturnV = m_glXWaitVideoSyncSGI(2, 0, &GlxTest);
+ if (ReturnV)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI returned %i", ReturnV);
+ return false;
+ }
+
+ m_glXGetVideoSyncSGI = (int (*)(unsigned int*))glXGetProcAddress((const GLubyte*)"glXGetVideoSyncSGI");
+ if (!m_glXGetVideoSyncSGI)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXGetVideoSyncSGI not found");
+ return false;
+ }
+
+ ReturnV = m_glXGetVideoSyncSGI(&GlxTest);
+ if (ReturnV)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXGetVideoSyncSGI returned %i", ReturnV);
+ return false;
+ }
+
+ return true;
+}
+
+void CVideoSyncGLX::Run(volatile bool& stop)
+{
+ unsigned int PrevVblankCount;
+ unsigned int VblankCount;
+ int ReturnV;
+ bool IsReset = false;
+ int64_t Now;
+
+ //get the current vblank counter
+ m_glXGetVideoSyncSGI(&VblankCount);
+ PrevVblankCount = VblankCount;
+
+ while(!stop && !m_displayLost && !m_displayReset)
+ {
+ //wait for the next vblank
+ ReturnV = m_glXWaitVideoSyncSGI(2, (VblankCount + 1) % 2, &VblankCount);
+ m_glXGetVideoSyncSGI(&VblankCount); //the vblank count returned by glXWaitVideoSyncSGI is not always correct
+ Now = CurrentHostCounter(); //get the timestamp of this vblank
+
+ if(ReturnV)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI returned %i", ReturnV);
+ return;
+ }
+
+ if (VblankCount > PrevVblankCount)
+ {
+ UpdateClock((int)(VblankCount - PrevVblankCount), Now);
+ IsReset = false;
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Vblank counter has reset");
+
+ //only try reattaching once
+ if (IsReset)
+ return;
+
+ //because of a bug in the nvidia driver, glXWaitVideoSyncSGI breaks when the vblank counter resets
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Detaching glX context");
+ ReturnV = glXMakeCurrent(m_Dpy, None, NULL);
+ if (ReturnV != True)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
+ return;
+ }
+
+ //sleep here so we don't busy spin when this constantly happens, for example when the display went to sleep
+ Sleep(1000);
+
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Attaching glX context");
+ ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ if (ReturnV != True)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
+ return;
+ }
+
+ m_glXGetVideoSyncSGI(&VblankCount);
+
+ IsReset = true;
+ }
+ PrevVblankCount = VblankCount;
+ }
+ m_lostEvent.Set();
+ while(!stop && m_displayLost && !m_displayReset)
+ {
+ Sleep(10);
+ }
+}
+
+void CVideoSyncGLX::Cleanup()
+{
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: Cleaning up GLX");
+ CSingleLock lock(g_graphicsContext);
+
+ if (m_vInfo)
+ {
+ XFree(m_vInfo);
+ m_vInfo = NULL;
+ }
+ if (m_Context)
+ {
+ glXMakeCurrent(m_Dpy, None, NULL);
+ glXDestroyContext(m_Dpy, m_Context);
+ m_Context = NULL;
+ }
+ if (m_Window)
+ {
+ XDestroyWindow(m_Dpy, m_Window);
+ m_Window = 0;
+ }
+
+ m_lostEvent.Set();
+ g_Windowing.Unregister(this);
+}
+
+float CVideoSyncGLX::GetFps()
+{
+ m_fps = g_graphicsContext.GetFPS();
+ return m_fps;
+}
+
+#endif
diff --git a/xbmc/video/videosync/VideoSyncGLX.h b/xbmc/video/videosync/VideoSyncGLX.h
new file mode 100644
index 0000000000..38d719defc
--- /dev/null
+++ b/xbmc/video/videosync/VideoSyncGLX.h
@@ -0,0 +1,55 @@
+#pragma once
+/*
+ * Copyright (C) 2005-2014 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if defined(HAS_GLX)
+
+#include "video/videosync/VideoSync.h"
+#include "system_gl.h"
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+#include "guilib/DispResource.h"
+#include "threads/Event.h"
+
+class CVideoSyncGLX : public CVideoSync, IDispResource
+{
+public:
+ virtual bool Setup(PUPDATECLOCK func);
+ virtual void Run(volatile bool& stop);
+ virtual void Cleanup();
+ virtual float GetFps();
+ virtual void OnLostDevice();
+ virtual void OnResetDevice();
+
+private:
+ int (*m_glXWaitVideoSyncSGI) (int, int, unsigned int*);
+ int (*m_glXGetVideoSyncSGI) (unsigned int*);
+
+ static Display* m_Dpy;
+ XVisualInfo *m_vInfo;
+ Window m_Window;
+ GLXContext m_Context;
+ volatile bool m_displayLost;
+ volatile bool m_displayReset;
+ CEvent m_lostEvent;
+};
+
+#endif
diff --git a/xbmc/windowing/osx/WinSystemIOS.h b/xbmc/windowing/osx/WinSystemIOS.h
index 049e0c8291..c34110a6e6 100644
--- a/xbmc/windowing/osx/WinSystemIOS.h
+++ b/xbmc/windowing/osx/WinSystemIOS.h
@@ -30,6 +30,7 @@
#include "threads/CriticalSection.h"
class IDispResource;
+class CVideoSyncCocoa;
class CWinSystemIOS : public CWinSystemBase, public CRenderSystemGLES
{
@@ -67,7 +68,8 @@ public:
virtual int GetNumScreens();
virtual int GetCurrentScreen();
- void InitDisplayLink(void);
+ void InitDisplayLink(CVideoSyncCocoa *syncImpl);
+ void VblankHandler(int64_t nowtime, double fps);
void DeinitDisplayLink(void);
double GetDisplayLinkFPS(void);
void OnAppFocusChange(bool focus);
@@ -85,6 +87,7 @@ protected:
CCriticalSection m_resourceSection;
std::vector<IDispResource*> m_resources;
bool m_bIsBackgrounded;
+ CVideoSyncCocoa *m_VideoSync;
private:
bool GetScreenResolution(int* w, int* h, double* fps, int screenIdx);
diff --git a/xbmc/windowing/osx/WinSystemIOS.mm b/xbmc/windowing/osx/WinSystemIOS.mm
index d1c7d64b94..5639a9604d 100644
--- a/xbmc/windowing/osx/WinSystemIOS.mm
+++ b/xbmc/windowing/osx/WinSystemIOS.mm
@@ -36,6 +36,7 @@
#include "utils/StringUtils.h"
#include "guilib/DispResource.h"
#include "threads/SingleLock.h"
+#include "video/videosync/VideoSyncCocoa.h"
#include <vector>
#undef BOOL
@@ -57,6 +58,7 @@ CWinSystemIOS::CWinSystemIOS() : CWinSystemBase()
m_iVSyncErrors = 0;
m_bIsBackgrounded = false;
+ m_VideoSync = NULL;
}
CWinSystemIOS::~CWinSystemIOS()
@@ -344,8 +346,15 @@ void CWinSystemIOS::OnAppFocusChange(bool focus)
(*i)->OnAppFocusChange(focus);
}
-void CWinSystemIOS::InitDisplayLink(void)
+void CWinSystemIOS::VblankHandler(int64_t nowtime, double fps)
{
+ if (m_VideoSync)
+ m_VideoSync->VblankHandler(nowtime, fps);
+}
+
+void CWinSystemIOS::InitDisplayLink(CVideoSyncCocoa *syncImpl)
+{
+ m_VideoSync = syncImpl;
}
void CWinSystemIOS::DeinitDisplayLink(void)
{