Posted: Wed Mar 02, 2011 12:22 pm
Is there a standard workaround to this without dropping Windows altogether?Dwedit wrote:DirectDraw provides horrible vblank waiting code, then SDL uses that horrible vblank waiting code.
Is there a standard workaround to this without dropping Windows altogether?Dwedit wrote:DirectDraw provides horrible vblank waiting code, then SDL uses that horrible vblank waiting code.
Prior to migrating my emulator to DX10 (where the problem has, apparently, been fixed), I would time the frame emulation and, if there were more than x milliseconds left before the next frame, I'd make a Sleep() call. The default granularity of Sleep() is 10ms, but if you want more accurate timing, it's possible to reduce it with another API call (don't remember what that call is...). Worked reasonably well.tepples wrote:Is there a standard workaround to this without dropping Windows altogether?Dwedit wrote:DirectDraw provides horrible vblank waiting code, then SDL uses that horrible vblank waiting code.
Yeah CPU usage is down to 15% (software) / 25% (opengl) now.FHorse wrote:and that's exactly what I do in the version uploaded last night after three beers
Or someone using while(1) with no delays (or even if they use delays, using too small of a delay). The renowned "amazing programmer" of Dwarf Fortress did this for many years; I wonder how many laptops he was responsible for destroying.Dwedit wrote:Because usually only bad vblank waiting code causes 100% CPU usage (of one core, don't be confused by numbers like "50% usage" on a dual core system), regardless of anything else.
koitsu wrote:Or someone using while(1) with no delays (or even if they use delays, using too small of a delay). The renowned "amazing programmer" of Dwarf Fortress did this for many years; I wonder how many laptops he was responsible for destroying.Dwedit wrote:Because usually only bad vblank waiting code causes 100% CPU usage (of one core, don't be confused by numbers like "50% usage" on a dual core system), regardless of anything else.
Code: Select all
volatile int new_flag, old_flag;
static void clock_me() { new_flag++; }
while(old_flag == new_flag) {
rest(1);
}
old_flag = new_flag;
Provided that one waiting function actually works for all sources of wakeup events in which a program is interested. For example, select() on Windows doesn't work on anything but network sockets. And can GetMessage() or select()/kqueue()/epoll() see vertical blanks?koitsu wrote:Many GUI-based libraries implement or wrap main() with their own routine to deal with this problem. On the Windows platform, the easiest way to halt things effectively is to use GetMessage() along with DispatchMessage() and TranslateMessage().
On UNIX and UNIX-like OSes, select() is a common choice, while other operating systems like FreeBSD offer things like kqueue() which are more efficient (and are very reminiscent of how Windows does it). Linux offers things like epoll(). Solaris offers things like poll(7d) (do not confuse this with poll(2), which is different).
Both "core environments" that I've used on Windows (Allegro and SDL) rely on a function in DirectX pre-10 known to use spin waiting. Good luck getting clarification out of Microsoft for best sleeping practice in DirectX pre-10 when Microsoft wants video game programmers to switch to a newer API that isn't ported to Windows XP so that it can get more users off of Windows XP and onto Windows 7.3) Spend the time to read up on whatever "core environment" you're using to find out if it wraps main() with its own routine. If there's no documentation, ask the author to explain how it works
Don't use (Windows|Linux|Mac OS X) at all? That almost sounds like console fanboys on Slashdot, who claim that individual independent game developers don't deserve to have a platform on which to make and self-publish a video game. Instead, they should move to a city and state with lots of established video game studios and work for ten years as an apprentice before putting their ideas into practice. I hope I misunderstood you.or don't use it at all.
I wouldn't use select() on Windows (I'm surprised it even exists), and Cygwin is a disgusting broken pile of shit -- please don't get me started on Cygwin, I can rant about it for weeks (and also do not respond with some nonsense like "well it works for me"; that's nice, it's still horribly broken -- there's too many reasons we're getting rid of it in our enterprise environment at my job and going pure Windows on our Win2K3 and 2K8 boxes). It's also not relevant to the discussion; we're not talking about how to accomplish POSIX on Win32, we're talking about how to not chew up 100% CPU time while waiting for VBL.tepples wrote:Provided that one waiting function actually works for all sources of wakeup events in which a program is interested. For example, select() on Windows doesn't work on anything but network sockets. And can GetMessage() or select()/kqueue()/epoll() see vertical blanks?
A spin wait/spin lock literally ties up the processor (a very small/short loop), and are heavily dependent upon their timeout/expire capability (hopefully being set to a VERY minimal/small value). This broken design methodology is documented on Windows as well as in general (see 2nd paragraph). For the Wikipedia link, see the section titled "Busy-waiting alternatives". You'll also see in that section that sleep() is mentioned. This is important. EDIT: There's also an article about spinlock alternatives which also delve into other options (such as switching threads; I wouldn't have thought of this, but sounds like an excellent method).tepples wrote:Both "core environments" that I've used on Windows (Allegro and SDL) rely on a function in DirectX pre-10 known to use spin waiting.
I understand/acknowledge the complaint, but all it means is more coding efforts required on the part of the application programmer. The programmer then has to use different design methodology for DX9 vs. DX10. Many implement this by defining separate models/methodologies if DX8 is detected vs. DX9 vs. DX10.tepples wrote:Good luck getting clarification out of Microsoft for best sleeping practice in DirectX pre-10 when Microsoft wants video game programmers to switch to a newer API that isn't ported to Windows XP so that it can get more users off of Windows XP and onto Windows 7.
This isn't what I said / what I intended. I said if you're using a graphics API or subsystem layer (example: Allegro), and it does not offer proper documentation outlining how the waiting methodology works, or the author cannot explain it, do not use the API/subsystem. This is in no way shape or form the same as "do not use {insert OS here}". There is no way I would advocate the latter; I am a vehement opponent of OS advocacy and a strong proponent of use-whatever-OS-suits-your-needs.tepples wrote:Don't use (Windows|Linux|Mac OS X) at all? That almost sounds like console fanboys on Slashdot ... I hope I misunderstood you.
Code: Select all
SDL-1.2.14/src/video/windx5/SDL_dx5video.c
439 static int DX5_FlipHWSurface(_THIS, SDL_Surface *surface);
...
2096 static int DX5_FlipHWSurface(_THIS, SDL_Surface *surface)
2097 {
...
2103 /* to prevent big slowdown on fast computers, wait here instead of driver ring 0 code */
2104 /* Dmitry Yakimov (ftech@tula.net) */
2105 while(IDirectDrawSurface3_GetFlipStatus(dd_surface, DDGBS_ISBLTDONE) == DDERR_WASSTILLDRAWING);
...
Yes, SDL HG has Direct3D/OpenGL blitters. Haven't tried it yet, but it does indeed use at least D3D9 for blits.koitsu wrote: I believe SDL 1.3 might use Direct3D instead -- which does VBL handling completely different (and more reliably from what I've been told by someone who does CUDA programming on a daily basis).