| 653 | } |
| 654 | |
| 655 | void FPSLimiter::FramerateLimit(int fpsTarget) |
| 656 | { |
| 657 | std::chrono::high_resolution_clock::time_point nowTimestamp = std::chrono::high_resolution_clock::now(); |
| 658 | double deltaTime = std::chrono::duration<double>(nowTimestamp - m_lastTimestamp).count(); |
| 659 | double targetDeltaTime = 1.0 / (double)fpsTarget; |
| 660 | double diffFromTarget = targetDeltaTime - deltaTime + m_prevError; |
| 661 | if (diffFromTarget > 0.0f) |
| 662 | { |
| 663 | size_t sleepInMs = std::min(1000, (int)(diffFromTarget * 1000)); |
| 664 | std::this_thread::sleep_for(std::chrono::milliseconds(sleepInMs)); |
| 665 | } |
| 666 | |
| 667 | auto prevTime = m_lastTimestamp; |
| 668 | m_lastTimestamp = std::chrono::high_resolution_clock::now(); |
| 669 | double deltaError = targetDeltaTime - std::chrono::duration<double>(m_lastTimestamp - prevTime).count(); |
| 670 | m_prevError = deltaError * 0.9 + m_prevError * 0.1; // dampen the spring-like effect, but still remain accurate to any positive/negative creep induced by our sleep mechanism |
| 671 | // clamp error handling to 1 frame length |
| 672 | if (m_prevError > targetDeltaTime) |
| 673 | m_prevError = targetDeltaTime; |
| 674 | if (m_prevError < -targetDeltaTime) |
| 675 | m_prevError = -targetDeltaTime; |
| 676 | // shift last time by error to compensate |
| 677 | m_lastTimestamp += std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(m_prevError)); |
| 678 | } |
| 679 | |
| 680 | bool CompressTextures(std::map<std::shared_ptr<donut::engine::LoadedTexture>, TextureCompressionType> & uncompressedTextures) |
| 681 | { |