Mouse Lag / Keyboard Lag / Direct3D Lag

If you develop for DirectX, there is one very common undesirable behavior which is not as spreaded as other problems. If you plan to create a quality product I recommend you to take the measures to prevent it.

Usually players interpret it as a mouse lag because they don’t feel the mouse responding to their commands and it is the only reference they have in the interaction with the application (on mouse based games). Other name this problem receive is “floaty cursor” since the mouse gives the sensation of being floating or sliding over a soapy surface. The Lag is not a few milisecond response lag, it can be of up to a second in some cases which makes the game unplayable.

Actually, the issue has nothing to do with the mouse, there are mouse input lags problems as well but this one is not the case. To better understand why a mouse lag problem isn’t a problem with the mouse handling code, you should think it as a sympthom of a seekness, but not necesarilly the cause of the problem. Most developers attempt to ignore this problem because of many reasons: they have never seen the problem, it is too much sporadic so it is really hard to track it and it doesn’t seem to be connected to any cause and so it is really hard to fix it. But you are very lucky! Here you might find a lot of valuable information about this problem.

The problem is tied to Direct3D, there isn’t evidence of this problem happening on OpenGL, most games that allow both render systems usually fix this problem when switching to OpenGL (so if you are a user which experiment this problem you can try doing this if the game allows you to do it)

The real problem actually occurs in the D3D handling code, the lag experienced by the player is no other than a lag in the scene presentation.

It is a bit tricky to reproduce it voluntarially since it requieres many conditions and often the problem appears and dissapears with minimal changes in the program or hardware configuration. It usually happens on machines with a CPU faster than the GPU, it is not tied to any specific hardware vendor but some graphic cards are more prone to present the problem. The program also must have some characteristics, like having few instructions (low ammount of D3D commands with low geometry) and a lot of work to do (mostly a lot of pixel drawing). With those conditions given what happens is that the d3d driver queue got filled more often than can be handled, but the queue is big enough to handle many frames of instructions before overflowing, hence the lag.

You might think “… but I have set the flip to wait for the vertical sync!”, even worse, this won’t do other thing than increase the problem because the command will represent more delay in the queue flow. Except if you wait for the vertical sync by yourself with the WaitForVerticalBlank DirectDraw command, which is not very used because it blocks the CPU, or polling the GetVerticalBlankStatus function.

In any case, the vertical sync behavior can be superseded by the graphic driver, and the command queue can be filled faster than the current vertical sync so it is not a guarantee to fix the problem.

If you manage to reproduce the problem in your computer, you can test adding a clock to the game and so you will see that it is displaying too much back-in-time compared to the system clock. As well you can test checking the response to the keyboard, you will note so that every event seems to be delayed, but this is just a perception effect, the logic is working just on time, it is just the displaying of it the one which is delayed. You can tie a sound to the keyboard input as well, you should be hearing the sound before the graphic response.

Do I have to worry about this problem?, if you did an extensive Q&A testing with enough number of representative machines of your target and it never appeared, and your game has not the characteristics described for this problem, I would say that you shouldn’t worry about. However, if it is the opposite, you haven’t done the Q&A or your code characteristic are the ones of this problem you’d better do something about.

What can you do about it?

One of the biggest problem with this issue is the extrange behavior some cards have when handling the DX_WAIT or DX_DONOTWAIT flag in the flip or blit commands. Some cards completelly ignore the DX_DONOTWAIT flag and never return the DXERR_WASSTILLDRAWING error code which would tell you that the last frame haven’t been finished yet.

So the problem is to find a way to not overload the driver queue. Unfortunatelly, there isn’t any Flush command in Direct3D to do so.

Rendering on fixed rate wouldn’t  fix this problem, supousse you send 30 frames per second to the card but it really can only handle 29 … after 30 seconds you will have a tail of 30 frames in the driver queue.

You need to eighter now that the queue command queue is empty (to do a graceful frameskip in case not) or to wait at some point for the card to finish the work. A third solution would be to fill the driver queue with garbage so commands would be executed inmediatelly or not executed, but I don’t find it an apropiated solution because you can end with a severe performance penality.

If you work with DX9 you can use DirectX Event Queries to check if a frame has been fully processed. To do so just issue the event in the command buffer just after the Present command, then you just need to poll if this event has been processed to know if the frame has been presented. It is up to you to create a good strategy for this to not stall the CPU when polling and give it the enough flexiblity to allow the game flow smoothly.

Now, if you work with DX8 or DX7 it isn’t as easy, the only way known to flush the commands buffer so far is to lock for reading a surface of the flipping chain with all the consecuent drawbacks, which in our case it is mostly the CPU stall waiting for the AGP data to get into the ram. You can try to reduce them by locking just a tiny region of the surface, and locking the next surface to be used (if you have a tripple buffer). Of course you will try to lock the backbuffer surface and not the primary one (Vista Aereo doesn’t like the primary buffer to be locked).

Locking the buffer seems to work perfectly on every machine, but you again need to create a good strategy to reduce the secondary effects, this strategy will depend on your rendering system and the one which work best for you might be different from others systems so it is a matter of testing and experiment.

- Juan Pablo

1 Comment »

  1. Rerriveaddibe Said,

    December 16, 2011 @ 10:31 pm

    list is endless.Birmingham Looking to revitalise that wardrobe? Satisfy your craving for shopping? Purchase karen millen dress clothes for evening occasions and special events, and Reiss, where the gentlemen can get their fill of karen millen clothing 011 summer show, the underwear, blouses, dresses, skirts, trousers, jackets, head scarves, handbags, flowers karen millen online there it is easy to get to the range of cafes in the Connswater Shopping Centre. I have mentioned the karen millen many more.Convent Garden is London’s trendy shopping area and you will find shopping in Covent Garden an karen millen dresses many more.Convent Garden is London’s trendy shopping area and you will find shopping in Covent Garden an

RSS feed for comments on this post · TrackBack URI

Leave a Comment