void CVideoSyncD3D::Run(CEvent& stopEvent) { int64_t Now; int64_t LastVBlankTime; int NrVBlanks; double VBlankTime; int64_t systemFrequency = CurrentHostFrequency(); // init the vblanktime Now = CurrentHostCounter(); LastVBlankTime = Now; m_lastUpdateTime = Now - systemFrequency; while (!stopEvent.Signaled() && !m_displayLost && !m_displayReset) { // sleep until vblank Microsoft::WRL::ComPtr<IDXGIOutput> pOutput; DX::DeviceResources::Get()->GetOutput(&pOutput); HRESULT hr = pOutput->WaitForVBlank(); // calculate how many vblanks happened Now = CurrentHostCounter(); 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, m_refClock); // save the timestamp of this vblank so we can calculate how many vblanks happened next time LastVBlankTime = Now; if ((Now - m_lastUpdateTime) >= systemFrequency) { float fps = m_fps; if (fps != GetFps()) break; } // because we had a vblank, sleep until half the refreshrate period because i think WaitForVBlank block any rendering stuf // without sleeping we have freeze rendering int SleepTime = (int)((LastVBlankTime + (systemFrequency / MathUtils::round_int(m_fps) / 2) - Now) * 1000 / systemFrequency); if (SleepTime > 50) SleepTime = 50; //failsafe if (SleepTime > 0) ::Sleep(SleepTime); } m_lostEvent.Set(); while (!stopEvent.Signaled() && m_displayLost && !m_displayReset) { Sleep(10); } }
void CVideoSyncAML::Run(CEvent& stopEvent) { // We use the wall clock for timout handling (no AML h/w, startup) std::chrono::time_point<std::chrono::system_clock> now(std::chrono::system_clock::now()); unsigned int waittime (3000 / m_fps); uint64_t numVBlanks (0); /* This shouldn't be very busy and timing is important so increase priority */ CThread::GetCurrentThread()->SetPriority(CThread::GetCurrentThread()->GetPriority() + 1); while (!stopEvent.Signaled() && !m_abort) { int countVSyncs(1); if( !g_aml_sync_event.WaitMSec(waittime)) { std::chrono::milliseconds elapsed(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now() - now).count()); uint64_t curVBlanks = (m_fps * elapsed.count()) / 1000; int64_t lastVBlankTime((curVBlanks * 1000) / m_fps); if (elapsed.count() > lastVBlankTime) { lastVBlankTime = (++curVBlanks * 1000) / m_fps; std::this_thread::sleep_for(std::chrono::milliseconds(lastVBlankTime - elapsed.count())); } countVSyncs = curVBlanks - numVBlanks; numVBlanks = curVBlanks; } else ++numVBlanks; uint64_t now = CurrentHostCounter(); UpdateClock(countVSyncs, now, m_refClock); } }
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); } }