DirectDraw7 Flip very slow

Started by
14 comments, last by Aardvajk 18 years, 1 month ago
Still banging on about this I'm afraid :) Bit of new info. I have old DirectDraw7 code that runs fast on a 98 machine but crawls on XP and 2000. After extensive tests I have discovered that it is the Flip operation that seems to be the bottleneck. Same with Direct3D7. Any ideas why this might be and how to correct it?
Advertisement
It might help if you posted your initialization code and your render/flip code so that we can see how things are set up and what parameters are being used.
How slow? Are you using an 8 bit target? WinXP has to emulate 8 bit mode, which may slow it down quite a bit.
Sean Henley [C++ Tutor]Rensselaer Polytechnic Institute
1) as has already been asked, how much slower is it on XP/2000?

a. knowing either the miliseconds-per-frame or frames-per-second you're seeing on 98, 2000, and XP would be handy for more suggestions.

b. one suspicion would be that the Flip()'s on the 98 machine aren't synchronised to the monitor refresh rate but those on the 2000 and XP machines are.
If the frames-per-second for the 2000 and XP machines are roughly the same as (or a rough lower multiple of) the monitor refresh rate set for those machines (e.g. 74.8fps & 75Hz, or 30fps & 60Hz), and the frames-per-second on the 98 machine is much higher than the monitor refresh rate (e.g. 400fps & 75Hz), then this is very likely to be the problem.

c. When Flip() is waiting for VSYNC, it will appear to take a long time when profiled - though it's [usually] not actually doing anything other than spinning in a loop checking a flag [a h/w register or s/w flag set by an interrupt handler].

d. if your Flip() is being synchronised/locked to the monitor refresh rate/VSYNC, unfortunately it isn't always entirely under your control: although you can specify flags to DirectDraw to tell it not to wait for VSYNC, some graphics card drivers have user options to override the wishes of your application/Direct3D/DirectDraw. Look deep in all the options of the Display properties for each of your test machines.


2) Which versions of DirectX do all of the machines have installed?, and do some have the Debug/SDK versions of DirectX active/installed whilst other have the Retail version?

a. If the Debug versions of DirectDraw or Direct3D are in use on the XP or 2000 machines, and the 98 has the Retail version, then that could account for some performance difference since the debug versions of the runtimes perform a whole lot more validation to make sure the API is being used properly.

b. On a related note, if your code is abusing the DirectDraw/Direct3D API in any way, then while the code may work on all of your test machines, the debug versions of the DirectDraw and D3D runtimes will complain lots whereas the Retail ones won't complain.

b. Another difference is the Debug Output Level sliders for all DirectX components (even seemingly unrelated ones). The 2000/XP machines may be outputting tons of information to the system debugger stream - which is slooow.


3) As well as the 8-bit emulation already mentioned above, 24-bit modes (rather than 32-bit ones) may also be particularly slow on some video cards too (most modern cards don't support 24-bit frame buffers natively)

Simon O'Connor | Technical Director (Newcastle) Lockwood Publishing | LinkedIn | Personal site

Initialisation code: (called with 640x480 and 32bit depth)

bool CDirectDraw::Acquire(HWND Hw,int W,int H,int D){    DDSURFACEDESC2 Ds;    DDSCAPS2 Dc;    DirectDrawCreateEx(NULL,(void**)&Draw,IID_IDirectDraw7,NULL);    Draw->SetCooperativeLevel(Hw,DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN);    Draw->SetDisplayMode(640,480,32,0,0);    ZeroMemory(&Ds,sizeof(Ds));    Ds.dwSize=sizeof(Ds);    Ds.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;    Ds.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;    Ds.dwBackBufferCount=2;    if(Draw->CreateSurface(&Ds,&Prim,NULL)!=DD_OK) return 0;    ZeroMemory(&Dc,sizeof(Dc));    Dc.dwCaps=DDSCAPS_BACKBUFFER;    if(Prim->GetAttachedSurface(&Dc,&Back)!=DD_OK) return 0;    return true;}


Flip code

void CDirectDraw::Flip(){    while(Prim->Flip(NULL,0)==DDERR_WASSTILLDRAWING);}


Have also tried

void CDirectDraw::Flip(){    Prim->Flip(NULL,DDFLIP_WAIT);}


On the newer PCs and OSs, if I blit one 32x32 sprite with not even clearing background it runs really really slow but if I blit loads of surfaces but only flip every other frame it runs twice as fast (although obviously graphics look jerky), which is why I assume it is the flip that is slowing things down. Have the same problem using Direct3D (older version where you use DirectDraw surfaces and still call DD flip).

Appreciate all the comments about the refresh rate - sounds very plausibly the problem. Is there any kind of solution if so or is my code above just wrong in some way?

Thanks
Sorry - just noticed I've got the backbuffercount set to 2 in the code above. Just tried it at 1 and doesn't make any difference. Sob.

Looked everywhere through the display properties on XP machine and can't find anything about synching with refresh rates.

I don't THINK I'm abusing the API in any way. Apart from the code above and some very standard initialising of surfaces, the only other DirectDraw code is calls to BltFast with or without SRCCOLORKEY flags for transparency.

My current test program on XP loads one 32x32 surface and blits it onto the back buffer without even clearing the buffer. Runs as slowly as the full blown platform game with hundreds of blits. Still convinced it is the flip. Help!
dont use flip unless you really need it. just blit the back buffer to the primary surface instead. it should improve the speed quite a bit.
twkr - appreciate the good idea but have just tried it and I get a similar effect to when I turn hardware acceleration off. Does get much much faster but the graphics get very blurry. I'm assuming this is because the copy is not synched with the vertical retrace although may be wrong.

Also, for some reason, when I do this the program won't shut down properly until I press Ctrl+Alt+Del. Bit weird.

This has at least confirmed to me that the Flip is what is slowing everything down though so cheers.
You still haven't posted any hard profiling statistics [wink]

Quote:Original post by EasilyConfused
Appreciate all the comments about the refresh rate - sounds very plausibly the problem. Is there any kind of solution if so or is my code above just wrong in some way?
As Simon mentioned - the synchronization flags are more hints than requirements. It's very common for drivers to allow these to be overriden by users - in which case there's nothing you can do [oh]

Another thought - are you doing frame-based animation/movement or time-based animation/movement?

I've come across older DDraw code before that uses frame-based animation (that is, all sprites move 1 unit each time a new frame comes around) that makes it very easy to get different performance characteristics on different machines. Time-based animation/modelling has it's problems, but this particular one shouldn't be an issue.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

What's the easiest way to time your framerate accurately? Happy to post some stats if someone can give me a couple of lines of code to do it. time.h?

However, have just tried passing DDFLIP_NOVSYNC to Flip and guess what - speeds up enormously but graphics go all shuddery again, so at least I now know exactly what the problem is.

Very confused now. How on earth do I get my nice solid-moving graphics back?

Must admit the code does use pixels-per-frame movement but surely if I move sprites based on time instead, the result will be really jerky on the hardware that is causing problems?

I'm going back to writing text adventures at this rate (all together now - probably a good idea based on your understanding of graphics code...)

This topic is closed to new replies.

Advertisement