// Apply Frame Limit and Display FPS info // This should only be called from VI void VideoThrottle() { u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ? (SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate; // Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2 if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t')) { u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS; u32 timeDifference = (u32)Timer.GetTimeDifference(); if (timeDifference < frametime) { Common::SleepCurrentThread(frametime - timeDifference - 1); } while ((u32)Timer.GetTimeDifference() < frametime) Common::YieldCPU(); //Common::SleepCurrentThread(1); } // Update info per second u32 ElapseTime = (u32)Timer.GetTimeDifference(); if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo) { UpdateTitle(); // Reset counter Timer.Update(); Common::AtomicStore(DrawnFrame, 0); DrawnVideo = 0; } DrawnVideo++; }
void ThrottleCallback(u64 last_time, int cyclesLate) { u32 time = Common::Timer::GetTimeMs(); int diff = (u32)last_time - time; bool frame_limiter = SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t'); u32 next_event = GetTicksPerSecond()/1000; if (SConfig::GetInstance().m_Framelimit > 2) { next_event = next_event * (SConfig::GetInstance().m_Framelimit - 1) * 5 / VideoInterface::TargetRefreshRate; } const int max_fallback = 40; // 40 ms for one frame on 25 fps games if (frame_limiter && abs(diff) > max_fallback) { WARN_LOG(COMMON, "system too %s, %d ms skipped", diff<0 ? "slow" : "fast", abs(diff) - max_fallback); last_time = time - max_fallback; } else if (frame_limiter && diff > 0) Common::SleepCurrentThread(diff); CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, last_time + 1); }
// Apply Frame Limit and Display FPS info // This should only be called from VI void VideoThrottle() { u32 TargetVPS = (SConfig::GetInstance().m_Framelimit > 2) ? (SConfig::GetInstance().m_Framelimit - 1) * 5 : VideoInterface::TargetRefreshRate; // Disable the frame-limiter when the throttle (Tab) key is held down. Audio throttle: m_Framelimit = 2 if (SConfig::GetInstance().m_Framelimit && SConfig::GetInstance().m_Framelimit != 2 && !Host_GetKeyState('\t')) { u32 frametime = ((SConfig::GetInstance().b_UseFPS)? Common::AtomicLoad(DrawnFrame) : DrawnVideo) * 1000 / TargetVPS; u32 timeDifference = (u32)Timer.GetTimeDifference(); if (timeDifference < frametime) { Common::SleepCurrentThread(frametime - timeDifference - 1); } while ((u32)Timer.GetTimeDifference() < frametime) Common::YieldCPU(); //Common::SleepCurrentThread(1); } // Update info per second u32 ElapseTime = (u32)Timer.GetTimeDifference(); if ((ElapseTime >= 1000 && DrawnVideo > 0) || g_requestRefreshInfo) { g_requestRefreshInfo = false; SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; if (ElapseTime == 0) ElapseTime = 1; u32 FPS = Common::AtomicLoad(DrawnFrame) * 1000 / ElapseTime; u32 VPS = DrawnVideo * 1000 / ElapseTime; u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime); // Settings are shown the same for both extended and summary info std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC"); // Use extended or summary information. The summary information does not print the ticks data, // that's more of a debugging interest, it can always be optional of course if someone is interested. //#define EXTENDED_INFO #ifdef EXTENDED_INFO u64 newTicks = CoreTiming::GetTicks(); u64 newIdleTicks = CoreTiming::GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; ticks = newTicks; idleTicks = newIdleTicks; float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100; std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)", _CoreParameter.bSkipIdle ? "~" : "", (int)(diff), (int)(diff - idleDiff), (int)(idleDiff), SystemTimers::GetTicksPerSecond() / 1000000, _CoreParameter.bSkipIdle ? "~" : "", TicksPercentage); #else // Summary information std::string SFPS; if (Movie::IsPlayingInput()) SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed); else if (Movie::IsRecordingInput()) SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed); else SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed); #endif // This is our final "frame counter" string std::string SMessage = StringFromFormat("%s | %s", SSettings.c_str(), SFPS.c_str()); std::string TMessage = StringFromFormat("%s | ", scm_rev_str) + SMessage; // Show message g_video_backend->UpdateFPSDisplay(SMessage.c_str()); if (_CoreParameter.bRenderToMain && SConfig::GetInstance().m_InterfaceStatusbar) { Host_UpdateStatusBar(SMessage.c_str()); Host_UpdateTitle(scm_rev_str); } else Host_UpdateTitle(TMessage.c_str()); // Reset counter Timer.Update(); Common::AtomicStore(DrawnFrame, 0); DrawnVideo = 0; } DrawnVideo++; }