I'd have to think about it but I think it would be because SDL_GetTicks() is probably not accurate to a fine level. This is the case with most timing functions, they are only really accurate on the large scale. What I imagine is happening is that some frames will be done too quickly (of course) and the code will wait for SDL_GetTicks() to tick over. Except, instead of jumping from 8 to 9 to 10 to 11 (which is 1000/90, the target), it might go something like 8, 8, 8, 15. That means that there is already 4ms wasted on this frame, and if this happens for most of the frames that would mean there is a deviation in framerate away from the cap.
First of all, here is a simplified version of your code. It uses a running total instead of recalculating and I have also removed the floating point divides as they are as good as equivilent to integer divides which are much faster.
Code:
#define MAX_FPS 90
typedef struct {
int fps;
Uint32 oldtime;
Uint32 newtime;
int limit;
int limitpress;
int index;
int sum; // running total
Uint32 list[MAX_FPS];
} FPS;
void setupFPS(FPS* fps)
{
int l;
for(l = 0; l < MAX_FPS; l++) {
fps->list[l] = 0;
}
fps->sum = 0;
}
void fpsCalc(FPS* fps, int MAX)
{
int d, i = 1000/MAX;
fps->oldtime = fps->newtime;
do {
fps->newtime = SDL_GetTicks();
d = fps->newtime - fps->oldtime;
} while (fps->limit && d < i);
fps->sum -= fps->list[fps->index];
fps->list[fps->index] = 1000/d;
fps->sum += fps->list[fps->index];
fps->fps = (fps->sum/MAX);
fps->index++;
if(fps->index > MAX - 1) fps->index = 0;
}
Now, the way round the cap delay is to not worry about serving a frame every 90th of a second, but rather to run frames as fast as possible and delay to push them towards an average.
Here is pseudo-code, which predicts the future frames timing and uses that to give frames at an average of 90fps:
Code:
#define MAX_FPS 90
#define FPSTIME (1000/(MAX_FPS))
nextframe = SDL_GetTicks() + FPSTIME;
while (game_loop)
{
while (SDL_GetTicks() > nextframe)
{
nextframe += FPSTIME;
game_logic();
}
critical_code();
}
If your rendering code and logic code are seperate, you might want to only render once after the frames have caught up. Of course this will make no difference if the framerate is high, but if it's low then it will give a significant boost. Here is a more advanced pseudo-code that also implements a minimum framerate and allows for cpu cycles to be freed for any background tasks using SDL_Delay(0).
Code:
#define MAX_FPS 90
#define MAX_FRAMESKIP 10
#define FPSTIME (1000/(MAX_FPS))
int skip;
nextframe = SDL_GetTicks() + FPSTIME;
while (game_loop)
{
if (SDL_GetTicks() > nextframe)
{
skip = 0;
while (SDL_GetTicks() > nextframe && skip++ < MAX_FRAMESKIP)
{
nextframe += FPSTIME;
game_logic();
}
game_render();
}
else
SDL_Delay(0); // release cpu briefly
critical_code();
}
If you want to pause the game or take the code focus out of the main loop, you would need to record how long for and add that on to nextframe...
Hope these ideas help.