Very strange behaviour with vsync on in window mode

Started by
9 comments, last by fabry 14 years, 6 months ago
Hi guys, I'm experiencing a strange behaviour while running my game engine inside a window with the vertical sync flag activated (D3DPRESENT_INTERVAL_ONE). That is when I drag my window outside the screen borders, the fps drops from 60Hz down to 30-40Hz depending on how big is the portion of the window outside the screen. The screen refresh rate of my laptop is set to 60Hz and I noticed that the lag is due to the time spent during the swap of the buffers in the device->Present() call that slowdown from a constant value of 16.6667 to values between 16.66667 and 35ms so that i don't have a fluid motion. The game engine has been developed in cpp on win xp SP3, directx 9.0c, graphic card is a Mobile Intel GMA 4500MHD I've noticed that the same problem regards other sources downloaded from tutorials found on internet so I think it could not depends on how i designed my engine but perhaps on the specific video card. Is there a way to fix this strange behaviour? Thanks in advance. Fabrizio
Advertisement
First: I've not tried it myself.

On WM_MOVE, you might try checking the window position against the desktop size to see if a portion of the client window is hidden. Change your viewport to render only what's visible. That may not help if Windows thinks the entire client rect is dirty.

You might try the above with the addition of setting the "dirty" rectangle to just what's visible.

Another thing to try: make sure your swapchain is created with D3DSWAPEFFECT_COPY and make sure your Present rect parameters reflect only the visible portion of the client rect.

Quote:i don't have a fluid motion

Are your updates based on seconds-per-frame each frame? If they're based on a fixed interval (an assumption that you're always getting 16mS per frame), you might want to change that. If you're going to do that, use a precision timer. Your mention of 16.667 and 35, etc., implies you're using timeGetTime perhaps and not the precision timer (QueryPerformanceFrequency and QueryPerformanceCounter).

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

Hi Buckeye,
thak you very much for your answer.

I'm using the D3DSWAPEFFECT_DISCARD flag instead of COPY and I call the Present with the statement device->Present(NULL, NULL, NULL, NULL) so the entire surface is always presented. Is it incorrect?

The way I update is "Constant Game Speed independent of Variable FPS" so the GameUpdate is called 25 times per second and the rendering is done as fast as possibile with interpolation (that is i call RenderGame(float interpolation)) as shown in the article "the game loop" (http://dewitters.koonsolo.com/gameloop.html)

In the GameUpdate function i have Sprite->position += speed
In the RenderGame function i have Sprite->viewposition += Sprite->position + speed * interpolation

The time function is timeGetTime() with timeBeginPeriod(1) and timeEndPeriod(1) with a precision of 1ms. Is it better to have a more accurate timer?
Quote:I'm using the D3DSWAPEFFECT_DISCARD flag instead of COPY and I call the Present with the statement device->Present(NULL, NULL, NULL, NULL) so the entire surface is always presented. Is it incorrect?

It's not incorrect if you always want to present the entire buffer (see the docs for IDirect3DDevice9::Present).

For the specific problem you're talking about, with a portion of the client outside the desktop, I thought perhaps it might be solved by presenting only a portion of the buffer. To do that, you'd need to use _COPY and add specific rectangles to the Present call.

Quote:The time function is timeGetTime() with timeBeginPeriod(1) and timeEndPeriod(1) with a precision of 1ms. Is it better to have a more accurate timer?

I agree that the docs claim a precision of 1ms. My experience (and a bit of googling on the subject) indicates that the actual "precision" depends on the machine and OS. Something like 10-15ms is probably a better assumption. If you choose to update based on actual seconds-per-frame rather than a fixed interval, you might want to consider using the performance counter rather than the system timer. Or, do some testing of the system timer and see if you're actually getting the precision you're assuming.

However, if you're using a fixed interval for updating, then the question is moot, right? Also, it sounds like you're updating 25 times per second (each 40ms) and "rendering is done as fast as possibile." You might consider D3DPRESENT_INTERVAL_IMMEDIATE and avoid the (slight) overhead. Be sure to check the devcaps to see what intervals are supported. I don't imagine that INTERVAL_ONE is not supported but you never know.

[WINK]If you believe the 1ms claim, then you shouldn't be relying on values like 16.6667. Maybe 16+/-1?

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

I'll try your advice, replacing with the _COPY flag, adding a specific rect to the preset and update the thread when finish, it could be useful for someone else.

You are right about the wrong value 16.6667 for swap time, this value comes from the operation '1000ms / number of rendering operation made in 1 second, about 60" = 16.6667, but when i calculate the delta time before and after the device->Present(), the value i get is always between 13-18 (as told before only when the window is inside the screen borders)

I've tried the flag D3DPRESENT_INTERVAL_IMMEDIATE but unfortunately i get bad tearing effects

Thank you very much again.
Fabrizio.
http://msdn.microsoft.com/en-us/library/ee416646(VS.85).aspx

D3DSWAPEFFECT_COPY has nothing to do with your problem. It makes Present call only slower.
Also, this "problem" is not something you should fix. It doesn't kill your PC, it doesn't make normal users enjoy the game less (after all, it will be runned in fullscreen mode, right?). You should change the window startup position to the center of screen instead.
Thanks Snake,
yes I can change the window startup position but i think it's not pretty to prevent the user to drag the window wherever he wants so if it's partially dragged outside the screen area he will experienced a slowdown.

Reading the doc at http://msdn.microsoft.com/en-us/library/ee416646(VS.85).aspx
it seems to me that with the D3DSWAPEFFECT_DISCARD flag i can only use NULL and cannot define a source rect for the Present method so i must swap the entire surface, even the portion not visible because outside the screen area. Am i wrong?

Thank you.
Fabrizio
My guess this is a limitation from your driver/video card.
You should try another system with a different video card, Intel's are usually pretty crap. May be you have luck on the Intel forums

I wouldn't be surprised if your driver, internally, falls back to COPY instead of DISCARD when the windows is partially outside the screen because the card can't handle it. That could explain it.
When you try COPY (all the time), does it slowdown in the same way, but only this time not only when the windows is out of the screen, but rather all the time?
Copying takes a lot more time than flipping a buffer, and the time it needs grows geometrically with the window resolution (unlike flipping/discard, which needs constant time and is very low). When you use VSync with Copy, the system will wait for the refresh, but due to the amount of time needed for the copy it may take more time, and still idle wait more than it should, slowing your frame rate.

Anyway, welcome to the windowed mode world!
In windowed mode, this stuff tends to happen (specially in WinXP). For example, my game (and all of them) experiences a similar slowdown when a MSN Messenger notification icon or similar appears in front of my app window, and I'm using a dedicated NVIDIA GPU!

Just being curious, your game isn't multithreaded, is it?
Because I've had the exact same problem due to some multithreading issues in my game engine when VSync was enabled (which I fixed by not messing up with SetThreadIdealProcessor, and disabling a console I was creating using AllocConsole and hooking stdio to it; yeah... I don't know how this is related to VSync, but it was causing trouble somehow when vsync was enabled)

Cheers
Dark Sylinc
Quote:but i think it's not pretty to prevent the user to drag the window wherever he wants

I'm not saying that you should prevent that. I'm just saying that you should not waste your time fixing things that 99.99% of the players will not notice..
EDIT:
Quote:Reading the doc at http://msdn.microsoft.com/en-us/library/ee416646(VS.85).aspx
it seems to me that with the D3DSWAPEFFECT_DISCARD flag i can only use NULL and cannot define a source rect for the Present method so i must swap the entire surface, even the portion not visible because outside the screen area. Am i wrong?

You don't need to define it if you're not looking for some special effects. No one ever draws something that is outside of any surface. You just don't have a destination pixel there... :)
Quote:Original post by snake5
Quote:but i think it's not pretty to prevent the user to drag the window wherever he wants

I'm not saying that you should prevent that. I'm just saying that you should not waste your time fixing things that 99.99% of the players will not notice..
EDIT:
Quote:Reading the doc at http://msdn.microsoft.com/en-us/library/ee416646(VS.85).aspx
it seems to me that with the D3DSWAPEFFECT_DISCARD flag i can only use NULL and cannot define a source rect for the Present method so i must swap the entire surface, even the portion not visible because outside the screen area. Am i wrong?

You don't need to define it if you're not looking for some special effects. No one ever draws something that is outside of any surface. You just don't have a destination pixel there... :)


And that is a pathological case anyhow. If the user is going out of their way to make your game slower, grats they succeeded (IMO :P).

btw something else is on dual monitor systems, usually only one monitor has hardware acceleration so your game will run faster on one monitor vs the other.

Thats another "pathological case" that you shouldnt worry about.

I think with your problem whats going on is that it has to use scisoring to cut the parts "off the screen" away from the parts on the screen when rendering and that extra clipping is what's slowing it down.

Im with everyone else though that your time is much better spent on other things (:

This topic is closed to new replies.

Advertisement