@@ -22,6 +22,96 @@ namespace lime {
2222 std::map<int , std::map<int , int > > gamepadsAxisMap;
2323 bool inBackground = false ;
2424
25+ static double nextFrac = 0.0 ;
26+ static double s_minSleepCostMs = 2.0 ; // initial estimate
27+ static bool s_minSleepCalibrated = false ;
28+
29+ static inline bool CanUseDelay1 (Uint32 remainingMs)
30+ {
31+ return remainingMs > (Uint32)(s_minSleepCostMs + 1.0 );
32+ }
33+
34+ static inline void CalibrateMinSleep ()
35+ {
36+ Uint32 t0 = SDL_GetTicks ();
37+ SDL_Delay (1 );
38+ Uint32 t1 = SDL_GetTicks ();
39+
40+ Uint32 observed = t1 - t0;
41+ if (observed < 1 ) observed = 1 ;
42+
43+ double observedD = (double )observed;
44+
45+ s_minSleepCostMs = (s_minSleepCostMs + observedD) * 0.5 ;
46+ s_minSleepCalibrated = true ;
47+ }
48+
49+ static inline Uint32 SleepMinStep ()
50+ {
51+ if (!s_minSleepCalibrated)
52+ CalibrateMinSleep ();
53+ else
54+ CalibrateMinSleep ();
55+
56+ return (Uint32)s_minSleepCostMs;
57+ }
58+
59+ static inline Uint32 NextFrameStep (double framePeriod) {
60+ Uint32 base = (Uint32)framePeriod;
61+ nextFrac += framePeriod - (double )base;
62+ if (nextFrac >= 1.0 ) { base++; nextFrac -= 1.0 ; }
63+ return base;
64+ }
65+
66+ static inline Sint32 GetFrameTimeRemaining (Uint32 nextUpdate)
67+ {
68+ Uint32 now = SDL_GetTicks ();
69+ Sint32 remaining = (Sint32)(nextUpdate - now);
70+ return remaining > 0 ? remaining : 0 ;
71+ }
72+
73+ static double s_delay1CostMs = 2.0 ;
74+ static bool s_delay1Calibrated = false ;
75+
76+ static inline void CalibrateDelay1 ()
77+ {
78+ Uint32 t0 = SDL_GetTicks ();
79+ SDL_Delay (1 );
80+ Uint32 t1 = SDL_GetTicks ();
81+
82+ double observed = (double )(t1 - t0);
83+ if (observed < 1.0 ) observed = 1.0 ;
84+
85+ s_delay1CostMs = (s_delay1CostMs + observed) * 0.5 ;
86+ s_delay1Calibrated = true ;
87+ }
88+
89+ static inline Uint32 SleepShortest (Uint32 timeRemainingMs)
90+ {
91+ if (!s_delay1Calibrated) {
92+ CalibrateDelay1 ();
93+ return 0 ;
94+ }
95+
96+
97+ // The "+1" is a small guard because observed delay is quantized and jittery
98+ if (timeRemainingMs > (Uint32)(s_delay1CostMs + 1.0 )) {
99+ Uint32 t0 = SDL_GetTicks ();
100+ SDL_Delay (1 );
101+ Uint32 t1 = SDL_GetTicks ();
102+
103+ double observed = (double )(t1 - t0);
104+ if (observed < 1.0 ) observed = 1.0 ;
105+
106+ s_delay1CostMs = (s_delay1CostMs + observed) * 0.5 ;
107+ return (Uint32)observed;
108+ }
109+
110+ // Otherwise, we're too close: yield instead of risking a multi-ms overshoot
111+ // Yield cost is scheduler-dependent so we don't try to model it here!
112+ SDL_Delay (0 );
113+ return 0 ;
114+ }
25115
26116 SDLApplication::SDLApplication () {
27117
@@ -41,8 +131,8 @@ namespace lime {
41131 currentApplication = this ;
42132
43133 framePeriod = 1000.0 / 60.0 ;
44-
45134 currentUpdate = 0 ;
135+
46136 lastUpdate = 0 ;
47137 nextUpdate = 0 ;
48138
@@ -135,12 +225,10 @@ namespace lime {
135225 applicationEvent.deltaTime = currentUpdate - lastUpdate;
136226 lastUpdate = currentUpdate;
137227
138- nextUpdate += framePeriod;
228+ nextUpdate += NextFrameStep ( framePeriod) ;
139229
140230 while (nextUpdate <= currentUpdate) {
141-
142- nextUpdate += framePeriod;
143-
231+ nextUpdate += NextFrameStep (framePeriod);
144232 }
145233
146234 ApplicationEvent::Dispatch (&applicationEvent);
@@ -989,9 +1077,23 @@ namespace lime {
9891077
9901078 if (!isBlocking) System::GCEnterBlocking ();
9911079 isBlocking = true ;
992- SDL_Delay (1 );
993- break ;
9941080
1081+ Uint32 now = SDL_GetTicks ();
1082+ Sint32 remaining = (Sint32)(nextUpdate - now);
1083+
1084+ if (remaining > 0 )
1085+ {
1086+ if (lime::CanUseDelay1 ((Uint32)remaining))
1087+ {
1088+ lime::SleepMinStep ();
1089+
1090+ }
1091+ else
1092+ {
1093+ SDL_Delay (0 );
1094+ }
1095+ }
1096+ break ;
9951097 }
9961098
9971099 }
0 commit comments