Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #620 from FernetMenta/atifix

fix VideoReferenceClock on ATI
  • Loading branch information...
commit 2f1b2c484f55e756cfe1227f4b1fd116c6c391bc 2 parents 18cfc9a + b51e47e
@FernetMenta FernetMenta authored
Showing with 119 additions and 35 deletions.
  1. +116 −35 xbmc/video/VideoReferenceClock.cpp
  2. +3 −0  xbmc/video/VideoReferenceClock.h
View
151 xbmc/video/VideoReferenceClock.cpp
@@ -30,6 +30,7 @@
#if defined(HAS_GLX) && defined(HAS_XRANDR)
#include <sstream>
#include <X11/extensions/Xrandr.h>
+ #include "windowing/WindowingFactory.h"
#define NVSETTINGSCMD "nvidia-settings -nt -q RefreshRate3"
#elif defined(__APPLE__) && !defined(__arm__)
#include <QuartzCore/CVDisplayLink.h>
@@ -228,6 +229,8 @@ bool CVideoReferenceClock::SetupGLX()
m_vInfo = NULL;
m_Context = NULL;
m_Window = 0;
+ m_pixmap = None;
+ m_glPixmap = None;
CLog::Log(LOGDEBUG, "CVideoReferenceClock: Setting up GLX");
@@ -267,6 +270,14 @@ bool CVideoReferenceClock::SetupGLX()
return false;
}
+ CStdString Vendor = g_Windowing.GetRenderVendor();
+ Vendor.ToLower();
+ if (Vendor.compare(0, 3, "ati") == 0)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: GL_VENDOR: %s, using ati workaround", Vendor.c_str());
+ m_bIsATI = true;
+ }
+
m_vInfo = glXChooseVisual(m_Dpy, DefaultScreen(m_Dpy), singleBufferAttributes);
if (!m_vInfo)
{
@@ -274,13 +285,26 @@ bool CVideoReferenceClock::SetupGLX()
return false;
}
- Swa.border_pixel = 0;
- Swa.event_mask = StructureNotifyMask;
- Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone );
- SwaMask = CWBorderPixel | CWColormap | CWEventMask;
+ if (!m_bIsATI)
+ {
+ Swa.border_pixel = 0;
+ Swa.event_mask = StructureNotifyMask;
+ Swa.colormap = XCreateColormap(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), m_vInfo->visual, AllocNone );
+ SwaMask = CWBorderPixel | CWColormap | CWEventMask;
- m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0,
+ m_Window = XCreateWindow(m_Dpy, RootWindow(m_Dpy, m_vInfo->screen), 0, 0, 256, 256, 0,
m_vInfo->depth, InputOutput, m_vInfo->visual, SwaMask, &Swa);
+ }
+ else
+ {
+ m_pixmap = XCreatePixmap(m_Dpy, DefaultRootWindow(m_Dpy), 256, 256, m_vInfo->depth);
+ if (!m_pixmap)
+ {
+ CLog::Log(LOGDEBUG, "CVideoReferenceClock: unable to create pixmap");
+ return false;
+ }
+ m_glPixmap = glXCreateGLXPixmap(m_Dpy, m_vInfo, m_pixmap);
+ }
m_Context = glXCreateContext(m_Dpy, m_vInfo, NULL, True);
if (!m_Context)
@@ -289,25 +313,32 @@ bool CVideoReferenceClock::SetupGLX()
return false;
}
- ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ if (!m_bIsATI)
+ ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ else
+ ReturnV = glXMakeCurrent(m_Dpy, m_glPixmap, 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)
+ if (!m_bIsATI)
{
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXWaitVideoSyncSGI not found");
- 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;
+ 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");
@@ -479,19 +510,6 @@ void CVideoReferenceClock::CleanupGLX()
{
CLog::Log(LOGDEBUG, "CVideoReferenceClock: Cleaning up GLX");
- bool AtiWorkaround = false;
- const char* VendorPtr = (const char*)glGetString(GL_VENDOR);
- if (VendorPtr)
- {
- CStdString Vendor = VendorPtr;
- Vendor.ToLower();
- if (Vendor.compare(0, 3, "ati") == 0)
- {
- CLog::Log(LOGDEBUG, "CVideoReferenceClock: GL_VENDOR: %s, using ati dpy workaround", VendorPtr);
- AtiWorkaround = true;
- }
- }
-
if (m_vInfo)
{
XFree(m_vInfo);
@@ -508,9 +526,19 @@ void CVideoReferenceClock::CleanupGLX()
XDestroyWindow(m_Dpy, m_Window);
m_Window = 0;
}
+ if (m_glPixmap)
+ {
+ glXDestroyPixmap(m_Dpy, m_glPixmap);
+ m_glPixmap = None;
+ }
+ if (m_pixmap)
+ {
+ XFreePixmap(m_Dpy, m_pixmap);
+ m_pixmap = None;
+ }
//ati saves the Display* in their libGL, if we close it here, we crash
- if (m_Dpy && !AtiWorkaround)
+ if (m_Dpy && !m_bIsATI)
{
XCloseDisplay(m_Dpy);
m_Dpy = NULL;
@@ -532,11 +560,59 @@ void CVideoReferenceClock::RunGLX()
m_glXGetVideoSyncSGI(&VblankCount);
PrevVblankCount = VblankCount;
+ uint64_t lastVblankTime = CurrentHostCounter();
+ int sleepTime, correction;
+ int integral = 0;
+
while(!m_bStop)
{
//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
+ if (!m_bIsATI)
+ {
+ ReturnV = m_glXWaitVideoSyncSGI(2, (VblankCount + 1) % 2, &VblankCount);
+ m_glXGetVideoSyncSGI(&VblankCount); //the vblank count returned by glXWaitVideoSyncSGI is not always correct
+ }
+ else
+ {
+ // calculate sleep time in micro secs
+ // we start with 50% of interval
+ sleepTime = 500000LL / m_RefreshRate;
+
+ // correct sleepTime by time used for processing since last vblank
+ correction = (CurrentHostCounter() - lastVblankTime) * 1000000LL / m_SystemFrequency;
+ sleepTime -= correction;
+
+ // correct sleep time by integral term
+ // consider 10 cycles as desired
+ sleepTime += integral;
+
+ // clamp sleepTime to a min value of 30% of interval
+ // integral is already clamped to a max value
+ sleepTime = std::max(int(300000LL/m_RefreshRate), sleepTime);
+
+ unsigned int iterations = 0;
+ while (VblankCount == PrevVblankCount && !m_bStop)
+ {
+ usleep(sleepTime);
+ m_glXGetVideoSyncSGI(&VblankCount);
+ sleepTime = sleepTime > 200 ? sleepTime/2 : 100;
+ iterations++;
+ }
+ if (iterations > 10)
+ integral += 100;
+ else if (iterations < 10)
+ integral -= 100;
+
+ // clamp integral to an absolute value of 20% of interval
+ if (integral > 200000LL/m_RefreshRate)
+ integral = 200000LL/m_RefreshRate;
+ else if (integral < -200000LL/m_RefreshRate)
+ integral = -200000LL/m_RefreshRate;
+
+ lastVblankTime = CurrentHostCounter();
+ ReturnV = 0;
+ }
+
Now = CurrentHostCounter(); //get the timestamp of this vblank
if(ReturnV)
@@ -554,13 +630,14 @@ void CVideoReferenceClock::RunGLX()
SingleLock.Leave();
SendVblankSignal();
UpdateRefreshrate();
-
IsReset = false;
}
- else
+ else if (!m_bStop)
{
CLog::Log(LOGDEBUG, "CVideoReferenceClock: Vblank counter has reset");
+ integral = 0;
+
//only try reattaching once
if (IsReset)
return;
@@ -575,7 +652,11 @@ void CVideoReferenceClock::RunGLX()
}
CLog::Log(LOGDEBUG, "CVideoReferenceClock: Attaching glX context");
- ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ if (!m_bIsATI)
+ ReturnV = glXMakeCurrent(m_Dpy, m_Window, m_Context);
+ else
+ ReturnV = glXMakeCurrent(m_Dpy, m_glPixmap, m_Context);
+
if (ReturnV != True)
{
CLog::Log(LOGDEBUG, "CVideoReferenceClock: glXMakeCurrent returned %i", ReturnV);
View
3  xbmc/video/VideoReferenceClock.h
@@ -119,9 +119,12 @@ class CVideoReferenceClock : public CThread
XVisualInfo *m_vInfo;
Window m_Window;
GLXContext m_Context;
+ Pixmap m_pixmap;
+ GLXPixmap m_glPixmap;
int m_RREventBase;
bool m_UseNvSettings;
+ bool m_bIsATI;
#elif defined(_WIN32) && defined(HAS_DX)
bool SetupD3D();
Please sign in to comment.
Something went wrong with that request. Please try again.