bool CWinSystemX11GL::PresentRenderImpl(const CDirtyRegionList& dirty) { CheckDisplayEvents(); if(m_iVSyncMode == 3) { glFinish(); unsigned int before = 0, after = 0; if(m_glXGetVideoSyncSGI(&before) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); glXSwapBuffers(m_dpy, m_glWindow); glFinish(); if(m_glXGetVideoSyncSGI(&after) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if(after == before) m_iVSyncErrors = 1; else m_iVSyncErrors--; if(m_iVSyncErrors > 0) { CLog::Log(LOGINFO, "GL: retrace count didn't change after buffer swap, switching to vsync mode 4"); m_iVSyncErrors = 0; m_iVSyncMode = 4; } if(m_iVSyncErrors < -200) { CLog::Log(LOGINFO, "GL: retrace count change for %d consecutive buffer swap, switching to vsync mode 2", -m_iVSyncErrors); m_iVSyncErrors = 0; m_iVSyncMode = 2; } } else if (m_iVSyncMode == 4) { glFinish(); unsigned int before = 0, swap = 0, after = 0; if(m_glXGetVideoSyncSGI(&before) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if(m_glXWaitVideoSyncSGI(2, (before+1)%2, &swap) != 0) CLog::Log(LOGERROR, "%s - glXWaitVideoSyncSGI - Returned error", __FUNCTION__); glXSwapBuffers(m_dpy, m_glWindow); glFinish(); if(m_glXGetVideoSyncSGI(&after) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if(after == before) CLog::Log(LOGERROR, "%s - glXWaitVideoSyncSGI - Woke up early", __FUNCTION__); if(after > before + 1) m_iVSyncErrors++; else m_iVSyncErrors = 0; if(m_iVSyncErrors > 30) { CLog::Log(LOGINFO, "GL: retrace count seems to be changing due to the swapbuffers call, switching to vsync mode 3"); m_iVSyncMode = 3; m_iVSyncErrors = 0; } } else if (m_iVSyncMode == 5) { int64_t ust, msc, sbc; if(m_glXGetSyncValuesOML(m_dpy, m_glWindow, &ust, &msc, &sbc)) m_glXSwapBuffersMscOML(m_dpy, m_glWindow, msc, 0, 0); else CLog::Log(LOGERROR, "%s - glXSwapBuffersMscOML - Failed to get current retrace count", __FUNCTION__); } else glXSwapBuffers(m_dpy, m_glWindow); return 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"); m_winSystem.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; std::istringstream Extensions(glXQueryExtensionsString(m_Dpy, m_winSystem.GetCurrentScreen())); std::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, m_winSystem.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, m_winSystem.GetWindow(), m_vInfo->visual, AllocNone ); SwaMask = CWBorderPixel | CWColormap | CWEventMask; m_Window = XCreateWindow(m_Dpy, m_winSystem.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 CGLContextGLX::SwapBuffers(int &mode) { if(mode == 3) { glFinish(); unsigned int before = 0, after = 0; if (m_glXGetVideoSyncSGI(&before) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); glXSwapBuffers(m_dpy, m_glxWindow); glFinish(); if(m_glXGetVideoSyncSGI(&after) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if (after == before) m_iVSyncErrors = 1; else m_iVSyncErrors--; if (m_iVSyncErrors > 0) { CLog::Log(LOGINFO, "GL: retrace count didn't change after buffer swap, switching to vsync mode 4"); m_iVSyncErrors = 0; mode = 4; } if (m_iVSyncErrors < -200) { CLog::Log(LOGINFO, "GL: retrace count change for %d consecutive buffer swap, switching to vsync mode 2", -m_iVSyncErrors); m_iVSyncErrors = 0; mode = 2; } } else if (mode == 4) { glFinish(); unsigned int before = 0, swap = 0, after = 0; if (m_glXGetVideoSyncSGI(&before) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if(m_glXWaitVideoSyncSGI(2, (before+1)%2, &swap) != 0) CLog::Log(LOGERROR, "%s - glXWaitVideoSyncSGI - Returned error", __FUNCTION__); glXSwapBuffers(m_dpy, m_glxWindow); glFinish(); if (m_glXGetVideoSyncSGI(&after) != 0) CLog::Log(LOGERROR, "%s - glXGetVideoSyncSGI - Failed to get current retrace count", __FUNCTION__); if (after == before) CLog::Log(LOGERROR, "%s - glXWaitVideoSyncSGI - Woke up early", __FUNCTION__); if (after > before + 1) m_iVSyncErrors++; else m_iVSyncErrors = 0; if (m_iVSyncErrors > 30) { CLog::Log(LOGINFO, "GL: retrace count seems to be changing due to the swapbuffers call, switching to vsync mode 3"); mode = 3; m_iVSyncErrors = 0; } } else glXSwapBuffers(m_dpy, m_glxWindow); }
void CVideoSyncGLX::Run(CEvent& stopEvent) { 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(!stopEvent.Signaled() && !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, m_refClock); 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(!stopEvent.Signaled() && m_displayLost && !m_displayReset) { Sleep(10); } }