2
\$\begingroup\$

I have a game which uses SFML, which in turn uses OpenGL.

When I run the game, it will use 100% CPU for (usually) about 24 seconds, and then immediately falls down to normal usage. I can't figure out what's going on during these 24 seconds. In some cases, it stays at 100% CPU usage forever, but it usually stops after 24 seconds.

I've attempted to profile it, but the most information I can get is that the time is all being spent in my OpenGL driver. Aside from this, I can't see any useful information. It's also unable to tell me who the caller of the offending OpenGL code is; instead, it just tells me that the caller is an 'Unknown Frame' called by main.

One interesting thing I've noticed is that although it's using 100% CPU, it has no negative effect on my game. It runs without any FPS loss or slow down. This makes me think that the problem may be in the code that's enforcing vsync.

Has anyone encountered this? Any ideas what it might be, or how I can go about figuring it out?

Also, to clarify, the game is single-threaded. The thread using 100% CPU is my game thread, not one of the background threads created by OpenGL.

EDIT : The problem is, in fact, vsync. It's enforced using OpenGL's wglSwapIntervalEXT function. If I disable it and use sleeps to limit my frame rate, CPU usage stays low. I still don't understand why it's behaving like this when vsync is enabled, though.

\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

It's probably the same issue as a DirectX. DirectX (and probably OpenGL) sit in a tight spin wait until the screen is ready to sync - this is probably to guarantee that the draw happens at the very next available sync.

You have figured out how to work around it yourself; but I found the following works better (you can still get tearing with your current code) - it reduced my CPU usage to 30% on an empty render loop.

set end = time for vsync after the next
while (time not within 10% before vsync and time < end)
   yield thread
end
perform present/wait for swap

Also you must NOT use Sleep() (unless you pass 0, which yields the thread) as it only has a resolution of ~15ms-30ms; which isn't nearly good enough for this. Use a high performance counter.

The basic idea is that we try to get within a certain range of the vsync - but and leave the rest up to DirectX/OpenGL. However, we don't sit around forever and wait - because we could miss it continually (we are yielding the thread after all); so rather give up at a certain point and let DirectX/OpenGL go into its tight loop.

You will also find more solutions described here.

\$\endgroup\$
4
  • \$\begingroup\$ This is what I had thought, but I don't understand why it usually stops spinning after a certain period of time. \$\endgroup\$
    – dauphic
    Oct 28, 2011 at 23:57
  • \$\begingroup\$ @dauphic probably because your game slows down as more entities etc. are created; or speeds up - it's all about how close you get to the vsync when you do your presentation routine. \$\endgroup\$ Oct 30, 2011 at 9:32
  • \$\begingroup\$ My game isn't actually doing anything. It starts at the title screen, which does nothing aside from rendering, and leave it alone until the CPU usage drops. I tested on a machine non-nVidia video card and it works fine, so I guess it's a nVidia driver issue. \$\endgroup\$
    – dauphic
    Oct 31, 2011 at 5:13
  • \$\begingroup\$ @dauphic it's quite possible that nVidia is falsely flagging your process for a compatibility hack - I don't know how approachable the they are for non-AAA developers. Try changing the name of your process (.exe) and see if that helps. \$\endgroup\$ Oct 31, 2011 at 10:10
1
\$\begingroup\$

More than likely, the driver does not want the CPU to run too many frames ahead of the CPU, so it waits for the GPU to complete it's current frame, before continuing to process the next draw instruction. Ideally, it would wait for some sort of interrupt and put the thread to sleep, but it sounds like it is just spinning on your config, and is likely polling the hardware or some piece of device mapped memory in a tight loop.

The more you render, the less time you will have to wait on the CPU - if you maintain the CPU having a short lead (using sleeps as you did - not that I recommend it unless you are trying to optimize power), the CPU won't have to wait for the GPU to catch up. This could explain the variable results you are seeing.

Also, compiling shaders may be another reason for high CPU usage on startup, but this is unlikely to go away by disabling vsync.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .