SDL_GL_SwapWindow too slow?

I just went to test my game on an older system and found the frame rate had suffered massive drops since last time I tested a couple months ago. After a bunch of testing I found that an empty loop with SDL_GL_SwapWindow was taking ~15ms on my newer Mac and 30+ on my older Mac. I can’t compile older versions now to see if SDL_GL_SwapWindow was drawing slow and I didn’t profile that call before because I thought all the action was happening in the gl* calls but maybe it was chugging back then too.

This code on my 2.7 GHz Intel Core i5 MacBook Pro (macOS 10.13) takes about 15ms per SDL_GL_SwapWindow call (in a 800x600 window none the less). Is this normal?

SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
	SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);	
	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);

	// create window	
	flags := SDL_WINDOW_SHOWN + SDL_WINDOW_OPENGL;
	if fullscreen then
		flags += SDL_WINDOW_FULLSCREEN;
		
	window := SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags);
	if window <> nil then
		begin		
			GLContext := SDL_GL_CreateContext(window);
			SDL_GL_MakeCurrent(window, GLContext);	   	
			SDL_GL_SetSwapInterval(1);
		end;
	
	nextTime := SDL_GetTicks + (1000 div 60);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity;
	glOrtho(0.0, width, height, 0, -10000, 10000);
	glViewPort(0, 0, width, height);

	while not quit do
		begin
			while SDL_PollEvent(event) > 0 do
			if event.type_ = SDL_QUIT_EVENT then
				quit := true;
	
			time := MillisecondsSinceNow;
			glClearColor(0, 0, 1, 1);
			glClear(GL_COLOR_BUFFER_BIT);

			SDL_GL_SwapWindow(window);
			MillisecondsPerSwap := MillisecondsSinceNow - time;
			writeln(MillisecondsPerSwap.str);

			SDL_Delay(TimeLeft(nextTime));
			nextTime += 1000 div 60;
			TotalFrameSinceStart += 1;
		end;

When vsync is enabled it doesn’t make much sense to measure the whole frame time (including waiting for vsync) and then sleep manually in addtiion to vsync. Sleeping is not that accurate and is probably causing you to miss a vsync.

I would check if vsync is enabled with SDL_GL_GetSwapInterval and if so, skip your own additional delay entirely. Or maybe make it a small constant like SDL_Delay(1) just to make sure you are not hogging all the cpu.

Also you should not assume that monitor refresh rate is always 60.

I wanted a fixed frame rate so I used this method. can I still get a fixed frame rate by not using SDL_delay? I don’t really understand what you’re proposing so I’m a little confused (example would be nice).

Even so I don’t understand why the manual delay would cause SDL_GL_SwapWindow to be slow. If I disable vsync and remove the call to SDL_delay I still get frames that are 18-30ms (and others that are 1-3) but that is for doing no working besides clearing the screen. Something seems wrong there.

Usually you can only depend on fixed frame rate if you are targeting a console or some other specific hardware. There are all kinds of solutions to the problem and I would instead do a fixed time step that is separate from the rendering FPS. This is however a bigger topic, so I wont go into that more. For more info see: https://gafferongames.com/post/fix_your_timestep/

On a 60Hz monitor just swapping the buffers with vsync should not take more than 16ms. If you think something is wrong you could add a glFlush before the swap and just time the SDL_GL_SwapWindow call to see how long waiting for vsync takes. (Well I’m not 100% if this will work)

All your event handling and draw code with glFlush (but without the call to SDL_GL_SwapWindow) should take under 16.666ms to for you to reach a steady 60fps. Try timing that instead of the swap time to find the actual culprit. Of course it’s possible there might be some mac quirks or maybe issues with the SDL bindings that you are using. I have little experience on those (What language is that? Pascal?).

You could also try calling SDL_GL_GetSwapInterval after SDL_GL_SetSwapInterval to see that you got what you asked for, as it’s not guaranteed.

Thanks, I’ll look into that. With just vsynch enabled I’m getting about a base of ~15ms in SDL_GL_SwapWindow so perhaps that is correct. The reason I was so curious about this is because I’m trying to track a performance problem but on my newer Mac I always get that base line of ~15ms regardless of what changes I make so it’s difficult to know where the problem is.

Are draw calls like dlDrawArrays deferred until swapping? I’m never getting more than a few ms on the entire update loop and a consistent 15ms during swapping but on the slower mac the swapping goes into the 30ms and frame rates sink to 30fps despite 4-5ms in the actual draw loop so again I’m don’t know where the performance is taking a hit.

Depending on the graphics hardware/drivers a lot of stuff is probably deferred. Like I said using glFlush might help

Ok, I sampled around a call to glFlush() and it turns out that’s where the ~15ms is coming from. If I turn of vsynch then I get numbers like:

> 15
> 3
> 26
> 1
> 15
> 2
> 27
> 1
> 14
> 1
> 27
> 1
> 16
> 2
> 26
> 2
> 3

I think this is just a red herring though. There’s probably something else that caused the recent performance problem and I got confused after sampling SDL_GL_SwapWindow. Thanks for helping.