Threading problems

Hi,

For my game I’ve written a sprite engine that uses OpenGL for all the
graphics rendering. It uses multi-threading to do its thing, and I’ve
encountered a frustrating issue. On the Mac there’s no problem, but on
Windows after about a minute of play the game starts to “stutter.” It
stops rendering (or swapping) for seconds at a time, drawing only one
frame every several seconds while the game logic continues to process
normally. The processing thread appears to be blocking the rendering
(main) thread for too long at just the moment when it would be nice to
have a little time to do the buffer swap. Here are the important
factors to know about my engine:

  1. The main thread handles all GL rendering.
  2. The secondary thread handles all game logic.
  3. I’ve enabled VSYNC to prevent tearing as things move around.
  4. I use a single mutex to coordinate the two threads.

The rendering loop looks like this:

glClear(GL_COLOR_BUFFER_BIT);

SDL_LockMutex(worldMutex);
while (layer) {
	layer->Render();
	layer = layer->nextLayer;
}

if (postRenderProc)
	postRenderProc(this);

SDL_UnlockMutex(worldMutex);	// *** RESUME LOGIC
SDL_GL_SwapBuffers();			// *** DO SWAP!

And the secondary (logic) thread calls this method:

int SS_World::ProcessThread()
{
while (!processQuit)
{
ticks = SDL_GetTicks();
if (processFlag)
{
GetInput();
SDL_LockMutex(worldMutex);
RunCollisionTest();
Process(); // process the world
Animate(); // process the world some more
SDL_UnlockMutex(worldMutex);
}
}

return 0;

}

Now, notice the two lines marked *** above. If I swap the lines and do
the swap before resuming the game logic then I lose up to a 60th of a
second of processing time for the game. On the Mac the game becomes
choppy. However on Windows it prevents the long delays in rendering. I
would prefer to keep them in the same order as shown.

What exactly is the “proper” way to coordinate threads and VSYNC so
that I can have the best of both worlds - the smoothest rendering and
the least interruption of processing?–
Scott Lahteine
Botfly Games

Well, the problem with pre-emptive multitasking is, when you don’t freely give
up time to the operating system when you have it, the operating system’ll
take it from your program - often at the worst possible time. This can’t be
avoided entirely, but if your progam’s reasonably polite it can be minimized.
So my suggestion is to insert SDL_Delay(10)'s in your code at times when it’s
waiting for something.On Sunday 06 April 2003 04:51 pm, Scott Lahteine wrote:

Hi,

For my game I’ve written a sprite engine that uses OpenGL for all the
graphics rendering. It uses multi-threading to do its thing, and I’ve
encountered a frustrating issue. On the Mac there’s no problem, but on
Windows after about a minute of play the game starts to “stutter.” It
stops rendering (or swapping) for seconds at a time, drawing only one
frame every several seconds while the game logic continues to process
normally. The processing thread appears to be blocking the rendering
(main) thread for too long at just the moment when it would be nice to
have a little time to do the buffer swap. Here are the important
factors to know about my engine:

  1. The main thread handles all GL rendering.
  2. The secondary thread handles all game logic.
  3. I’ve enabled VSYNC to prevent tearing as things move around.
  4. I use a single mutex to coordinate the two threads.

The rendering loop looks like this:

glClear(GL_COLOR_BUFFER_BIT);

SDL_LockMutex(worldMutex);
while (layer) {
layer->Render();
layer = layer->nextLayer;
}

if (postRenderProc)
postRenderProc(this);

SDL_UnlockMutex(worldMutex); // *** RESUME LOGIC
SDL_GL_SwapBuffers(); // *** DO SWAP!

And the secondary (logic) thread calls this method:

int SS_World::ProcessThread()
{
while (!processQuit)
{
ticks = SDL_GetTicks();
if (processFlag)
{
GetInput();
SDL_LockMutex(worldMutex);
RunCollisionTest();
Process(); // process the world
Animate(); // process the world some more
SDL_UnlockMutex(worldMutex);
}
}

return 0;
}

Now, notice the two lines marked *** above. If I swap the lines and do
the swap before resuming the game logic then I lose up to a 60th of a
second of processing time for the game. On the Mac the game becomes
choppy. However on Windows it prevents the long delays in rendering. I
would prefer to keep them in the same order as shown.

What exactly is the “proper” way to coordinate threads and VSYNC so
that I can have the best of both worlds - the smoothest rendering and
the least interruption of processing?

i have a question…why use threads here? Threads arent magical sources of
multitasking, they take up cpu time and add overhead and can cause things to
fall out of sync like youve seen. If you want things to happen in
intervals, ive found atleast its best to use a single thread and just keep
track of how much time has passed (using SDL_GetTicks), and process things
whenever enough time has passed (:> ----- Original Message -----

From: slur@qwest.net (Scott Lahteine)
To:
Sent: Sunday, April 06, 2003 3:51 PM
Subject: [SDL] Threading problems

Hi,

For my game I’ve written a sprite engine that uses OpenGL for all the
graphics rendering. It uses multi-threading to do its thing, and I’ve
encountered a frustrating issue. On the Mac there’s no problem, but on
Windows after about a minute of play the game starts to “stutter.” It
stops rendering (or swapping) for seconds at a time, drawing only one
frame every several seconds while the game logic continues to process
normally. The processing thread appears to be blocking the rendering
(main) thread for too long at just the moment when it would be nice to
have a little time to do the buffer swap. Here are the important
factors to know about my engine:

  1. The main thread handles all GL rendering.
  2. The secondary thread handles all game logic.
  3. I’ve enabled VSYNC to prevent tearing as things move around.
  4. I use a single mutex to coordinate the two threads.

The rendering loop looks like this:

glClear(GL_COLOR_BUFFER_BIT);

SDL_LockMutex(worldMutex);
while (layer) {
layer->Render();
layer = layer->nextLayer;
}

if (postRenderProc)
postRenderProc(this);

SDL_UnlockMutex(worldMutex); // *** RESUME LOGIC
SDL_GL_SwapBuffers(); // *** DO SWAP!

And the secondary (logic) thread calls this method:

int SS_World::ProcessThread()
{
while (!processQuit)
{
ticks = SDL_GetTicks();
if (processFlag)
{
GetInput();
SDL_LockMutex(worldMutex);
RunCollisionTest();
Process(); // process the world
Animate(); // process the world some more
SDL_UnlockMutex(worldMutex);
}
}

return 0;
}

Now, notice the two lines marked *** above. If I swap the lines and do
the swap before resuming the game logic then I lose up to a 60th of a
second of processing time for the game. On the Mac the game becomes
choppy. However on Windows it prevents the long delays in rendering. I
would prefer to keep them in the same order as shown.

What exactly is the “proper” way to coordinate threads and VSYNC so
that I can have the best of both worlds - the smoothest rendering and
the least interruption of processing?


Scott Lahteine
Botfly Games


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl