Fix for DirectX 7 latency on Windows 7?
Asked Answered
S

1

6

We have a piece of software that is programmed against DirextX 7 SDK (i.e the code uses LPDIRECTDRAWSURFACE7 and the likes) and runs in fullscreen. The main task is putting something on the screen in response to external triggers in a reliable manner. This behaves very well on Windows XP: bsically the software waits for some trigger and when triggered, creates a new frame, puts it in the backbuffer, then tells DX to flip the buffers. The result is the approximate delay between the trigger and when the frame is effectively shown on the screen is, depending on video card and drivers, 3 frames or 50mSec for a 60Hz screen. This is tested on a variety of systems, all running NVidia cards. On some systems with higher end cards we even get 2 frames.

When running the same software on Windows 7 (with no other software installed at all) however, we cannot get lower than 5 frames. Meaning somewhere in the pipeline the OS or driver or both eat 2 extra frames, which is near to unacceptable for the application. We tried disabling aero/desktop composition/different driver versions/different video cards but no avail.

  • where does this come from? is this documented somewhere?
  • is there an easy way to fix? I know DirectX 7 is old, but upgrading to compile agains a more recent version might be tons of work so another type of fix would be nice. Maybe some flag that can be set in code?

edit here's some code which seems relevant:

Creation of front/back surfaces:

ddraw7->SetCooperativeLevel( GetSafeHwnd(),
  DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWMODEX | DDSCL_MULTITHREADED )

DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof( desc );
desc.dwFlags =  DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
desc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP |
                      DDSCAPS_COMPLEX | DDSCAPS_3DDEVICE |
                      DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM;
desc.dwBackBufferCount = 1;
ddraw7->CreateSurface( &desc, &primsurf, 0 )

DDSCAPS2 surfcaps;
ZeroMemory( &surfcaps,sizeof( surfcaps ) );
surfcaps.dwCaps = DDSCAPS_BACKBUFFER;
primsurf->GetAttachedSurface( &surfcaps, &backsurf );

Creation of surfaces used to render frames before they get drawn:

DDSURFACEDESC2 desc;
ZeroMemory( &desc, sizeof(desc) );
desc.dwSize = sizeof(desc);
desc.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS ;
desc.dwWidth = w;
desc.dwHeight = h;
desc.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY;
desc.ddpfPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
desc.ddpfPixelFormat.dwFlags = DDPF_PALETTEINDEXED8;

LPDIRECTDRAWSURFACE7 surf;
HRESULT r=ddraw7->CreateSurface( &desc, &surf, 0 )

Rendering loop, in OnIdle:

//clear surface
DDBLTFX bltfx;
ZeroMemory( &bltfx, sizeof(bltfx) );
bltfx.dwSize = sizeof( bltfx );
bltfx.dwFillColor = RGBtoPixel( r, g, b );
backsurf->Blt( rect, 0, 0, DDBLT_COLORFILL | DDBLT_WAIT, &bltfx )

//blit some prerendered surface onto it, x/y/rect etc are calculated properly)
backsurf->BltFast( x, y, sourceSurf, s&sourceRect, DDBLTFAST_WAIT );

primsurf->Flip( 0, DDFLIP_WAIT )

primsurf->Blt(&drect,backsurf,&srect,DDBLT_WAIT,0);
Spacecraft answered 21/5, 2013 at 10:48 Comment(17)
Care to explain why this is downvoted? If it doesn't belong here for instance, at least tell why.Spacecraft
ask it on stackoverflow, because this a coding question.Chloric
yeah I wasn't sure, it's possible that it is just some configuration issue - anyway voted to close to move to SOSpacecraft
See if disabling vertical synchronization in your graphics card panel helps.Saint
It's probably a driver issue - newer graphics cards/drivers use DX9/10 to emulate DX7, which is possibly causing the delays.Pentarchy
@Saint it's near to impossible to test since disabling VSync screws up the reference images needed to check timing - so even if it fixed timing, it would be unusable since it's not displaying the frames reliablySpacecraft
Is the application running with 2-3 frames when executed in XP compatibility mode (on win7)? If so you could write a launcher that would set the compatibility mode based on the OS.Devindevina
@FlorisVelleman tried it, no avail..Spacecraft
Are you sure it's not the processing of the external trigger that causes the delay instead of DX? What is the trigger and how is it processed?Invagination
for testing timing we don't use the external trigger: we just display one white frame followed by 9 black frames, or some variation, you get the point.Spacecraft
What's your locking strategy?... and since this is now on SO, can you post some code please?Journal
@Journal locking on what? what code do you want to see exactly? as said, it's basically just creating a DIRECTDRAW7 and a couple of DIRECTDRAWSURFACE7, filling them with pixels and alling Flip() on the primary surface (that's what I got from a small investigation, it's a huge codebase and not mine)Spacecraft
@Spacecraft I'd like to see exactly that code. The Blt calls, the Flip and anything closely related to them (e.g. locking).Journal
@Spacecraft IIRC (it's been a very long time) blting is an asynchronous operation, so generally you'd either lock the backbuffer for drawing (and unlock when all writes had ended) or use the DDBLT_WAIT flag on the Blt call to force sync behaviour. It would be interested to switch modes and see what happened. Combine that with some stopwatch tests and you could rule out DDERR_WASSTILLDRAWING at the time of the flip as an issue.Journal
@Journal see edit.. it took me almost an hour to extract this, that alone is a solid indication we're probably better of rewriting the thing from scrathSpacecraft
@stijin If DDFLIP_DONOTWAIT were set on the flip, it would be interesting to see how long it returned DDERR_WASSTILLDRAWING for before letting the operation pass. If that's where your frames are being gobbled up, it implies there's another op causing the issue. If it's not, then it points the finger at the flip operation. The latter implies the emulation layer is solely at fault, the former implies there may be some other aspect of your code that could be tweaked.Journal
@Journal not a bad idea. Measured it, it's exactly one frame.Spacecraft
D
3

I think that the Windows XP thing is a red herring. The last version of Windows that ran DirectX 7 directly was Windows 2000. Windows XP is just emulating DX7 in DX9, same as Windows 7 is doing.

I'll venture a guess that your application uses palettized textures, and that when DX emulates that functionality (as it was dropped after DX7) it's generating a texture using the indexed colors. You might try profiling the app with GPUView to see if there's a delay in pushing the texture to the GPU. E.g., perhaps the Win7 driver compressing it first?

Disengage answered 26/6, 2013 at 23:38 Comment(3)
we're not using palettized textures, or any other special DX fecture: everything gets written pixel by pixel directly to the surface memory. But thanks for mentioning GPUView, didn't know it but it seems mighty interesting.Spacecraft
@Spacecraft are you running any shaders?Disengage
no; don't have the code atm but afaik the render loop just sets some pixels in a surface, blits the surface onto the backbuffer surface and calls Flip()Spacecraft

© 2022 - 2024 — McMap. All rights reserved.