Sign in to follow this  
NightCabbage

Direct3D 9 Framerate Limited...

Recommended Posts

NightCabbage    100
Hey all I've got a really simple program here (C++, DX9) - just rendering a quad. I've opened up FRAPS, and it tells me that it's only running at about 30-40fps... and about 0-1% CPU. Is there something I need to do to prevent it from limiting the framerate? If it was stuck at about 60fps, I'd assume v-sync was on... but 40fps? So maybe I need to tell it "hey, actually use some CPU time to render as many frame as you can"? Render function is just this:
    p_dx_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
    p_dx_Device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
    p_dx_Device->BeginScene();

    p_dx_Device->SetStreamSource(0, p_dx_VertexBuffer, 0, sizeof(QUADVERTEX));
    p_dx_Device->SetFVF(QUADVERTEXFVF);

    p_dx_Device->DrawPrimitive(D3DPT_TRIANGLEFAN, 0, 2);

    p_dx_Device->EndScene();
    p_dx_Device->Present(NULL, NULL, NULL, NULL);
And message loop is just this:
    while(appRunning)
    {
        while(PeekMessage(&msg_Message, han_Window, 0, 0, PM_REMOVE))
        {
            TranslateMessage(&msg_Message);
            DispatchMessage(&msg_Message);
        }
        DrawScene(p_Device, p_dx_VB);
    }

Share this post


Link to post
Share on other sites
NightCabbage    100
Quote:
Original post by Steve_Segreto
It would be nice to also see how you create your device.

Good point :)

    LPDIRECT3D9 p_dx_Object;
LPDIRECT3DDEVICE9 p_dx_Device;

p_dx_Object = Direct3DCreate9(D3D_SDK_VERSION);

D3DPRESENT_PARAMETERS dx_PresParams;
ZeroMemory(&dx_PresParams, sizeof(dx_PresParams));
dx_PresParams.Windowed = TRUE;
dx_PresParams.SwapEffect = D3DSWAPEFFECT_DISCARD;
dx_PresParams.BackBufferFormat = D3DFMT_X8R8G8B8;
dx_PresParams.EnableAutoDepthStencil = TRUE;
dx_PresParams.AutoDepthStencilFormat = D3DFMT_D16;


Quote:
Also you might want to just process one windows message per drawScene call rather than emptying the queue of windows messages.

Oh, I thought that this would mean that each frame would only get one message?
And thus, if the user presses more than one key, or moves the mouse, it will take many frames for the game to catch up?

I ran into this problem a while ago:
http://www.gamedev.net/community/forums/topic.asp?topic_id=530473

Share this post


Link to post
Share on other sites
Programmer16    2321
Message queue code should handle all the messages available, not one per-frame (meaning your code is right on that part.) However, you don't handle seem to handle WM_QUIT, which is not good.


p_dx_Device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);
p_dx_Device->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);



This however, should just be:

p_dx_Device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255, 255, 255), 1.0f, 0);



And vertical-sync is most definitely on (unless you have some other app disabling it.) To disable it, you set PresentParameters::PresentationInterval to D3DPRESENT_INTERVAL_IMMEDIATE.

Beyond that, you haven't shown much code, so I can't really say.

If you need a tutorial to help you with the back-side of things, I'd recommend these articles. His articles cover a lot of the not-so-well-covered stuff (like message queues, lost devices, etc.)

HTH!

Share this post


Link to post
Share on other sites
NightCabbage    100
Quote:
Original post by Programmer16
However, you don't handle seem to handle WM_QUIT, which is not good.

I deal with the particular messages in my WndProc function, is that ok?

Quote:
D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER

Cool, thanks for the tip!

Quote:
And vertical-sync is most definitely on (unless you have some other app disabling it.) To disable it, you set PresentParameters::PresentationInterval to D3DPRESENT_INTERVAL_IMMEDIATE.

Perfect, this fixed it :)

Though I find it interesting that it was limiting it to about 30-40fps, and not 60!

Thanks!

Share this post


Link to post
Share on other sites
marius1930    119
Quote:
Original post by Steve_SegretoAlso you might want to just process one windows message per drawScene call rather than emptying the queue of windows messages.


That would severely limit the application. Worst idea ever.
With some mouse movement and keyboard interaction you're easily looking at 20 messages that needs to be processed per frame in order to get the correct/intended result.

Quote:
Original post by NightCabbage
Though I find it interesting that it was limiting it to about 30-40fps, and not 60!


D3DPRESENT_INTERVAL_ONE will limit it at 60 fps (assuming 60Hz monitor)
D3DPRESENT_INTERVAL_DEFAULT will limit it at the 30-40 you're seeing.

Quote:
MSDN
D3DPRESENT_INTERVAL_DEFAULT uses the default system timer resolution whereas the D3DPRESENT_INTERVAL_ONE calls timeBeginPeriod to enhance system timer resolution. This improves the quality of vertical sync, but consumes slightly more processing time. Both parameters attempt to synchronize vertically.

Share this post


Link to post
Share on other sites
NightCabbage    100
Quote:
Original post by Programmer16
If you need a tutorial to help you with the back-side of things, I'd recommend these articles. His articles cover a lot of the not-so-well-covered stuff (like message queues, lost devices, etc.)

Best tutorial I've seen. Highly recommended!

Thanks for the link!

Share this post


Link to post
Share on other sites
Adam Hamilton    271
Can anyone tell me why you would want to render as many frames as possible with spare CPU time. I have always believed that you should try and limit the FPS of the rendering to the refresh rate of the monitor, sending the extra bandwidth to update calls

I guess the only benefit I can see is if the rendering is done to off-screen render targets and shader programs running through algorithms that don't necessarily write to the screen. I am not sure if this is right - I am just starting to get into Direct3D programming and it would be good to know in any case.

I guess the only other use I can come up with is benchmarking the card / CPU


Cheers
Adam Hamilton

Share this post


Link to post
Share on other sites
NightCabbage    100
There's no particular reason - some people like to run with vsync turned off.

Also you bring up another point... "sending the extra bandwidth to update calls"

What's the best way to do this?

eg. isn't the update call done before the draw call (one after the other - once per frame)?

and would there be any point in updating more than once per frame?

Share this post


Link to post
Share on other sites
Regarding the absurdly high framerates, yes, they're a bit useless, aside from benchmarks and bragging rights. If DirectX supported the useful method of triple buffering, the extra fast rendering could reduce input lag and show no tearing, however DirectX doesn't support the useful method of triple buffering.

The other benefit of not being vertical synced is when you can't guarantee 60Hz. Most people would rather get a smoothly fluctuating frame rate with some mild tearing rather than sudden jumps between 30Hz and 60Hz (and/or 20Hz).

-

I know you're going to ask about that useful vs. useless triple buffering, as it's not common knowledge... I only read about it earlier this year, and it makes so much sense.

Under DirectX, the buffers are always shown in the order they were rendered. A third buffer just mean everything is delayed by 1 scene draw without vsync, or 1 frame with vsync. In the useful triple buffer method, when the front and backbuffers are swapped, the old front buffer swaps with the backbuffer that is not currently drawing. If no new frame is ready at vsync time, the existing buffer stays the front buffer.

Lets assume you can render 3 times faster than 60Hz, or 5-6ms per frame.

What DirectX does for triple buffering without vsync.
Render to backbuffer 1.
Render to backbuffer 2.
DirectX will show backbuffer 1 (5-6ms old, may have tearing)
Render to backbuffer 1.
DirectX will show backbuffer 2 (5-6ms old, may have tearing)
Render to backbuffer 2.
DirectX will show backbuffer 1 (5-6ms old, may have tearing)

What DirectX does for triple buffering with vsync enabled.
Render to backbuffer 1.
Render to backbuffer 2.
DirectX will show backbuffer 1 (5-6ms old)
Render to backbuffer 1.
DirectX will show backbuffer 2 (10.6-11.6ms old (16.666ms - 5-6ms to render))
Render to backbuffer 2.
DirectX will show backbuffer 1 (10.6-11.6ms old (16.666ms - 5-6ms to render))
These frame times may get even longer as we stall, waiting for the buffers in the render queue to be presented.

The useful triple buffering system is as follows... vsync enabled.
Render to backbuffer 1.
Render to backbuffer 2.
Render to backbuffer 1.
Something other than DirectX takes the latest ready frame.
Render to backbuffer 2.
Render to backbuffer 1.
Render to backbuffer 2.
Something other than DirectX takes the latest ready frame.
In this case the latest frame is always between 0 and 5-6ms behind, as we might have just finished drawing it, or we might be just about to finish, and so at worst, the last fully drawn frame was 5-6ms ago.

Share this post


Link to post
Share on other sites
Hodgman    51234
Quote:
Original post by NightCabbage
eg. isn't the update call done before the draw call (one after the other - once per frame)?

and would there be any point in updating more than once per frame?
If you turn that question around to "is there any point in rendering less than once per update", then the answer might be yes ;)

e.g. game logic often happens at a fixed frequency (no variable time-steps), which means you can't skip an update-frame... but if you're FPS drops, you can safely skip a render-frame.

Share this post


Link to post
Share on other sites
NightCabbage    100
Sounds almost like the update and render loops should be running in different threads...

How do most normal engines deal with this? (ie. skipping render frames)

Do they do it manually? (ie. check framerate and then skip a render if necessary)

Share this post


Link to post
Share on other sites
Adam Hamilton    271
I am not sure but I have seen something similar to this



TargetFPS = 60.0
SecPerFrame = 1.0 / TargetFPS -- Will be about 16.66ms

do
FrameTime = 0
do
deltaTime = GetDeltaTime()
Update(deltaTime)
FrameTime = FrameTime + deltaTime
while FrameTime < SecPerFrame
Render()
while GameStillRunning





Although this may tend to cause your frame rate to drop to half your target speed so what I would do is is minus a millisecond from the SecPerFrame so that you are sure you are going to call that render function before your frame time reaches 16.66ms (in the case of 60FPS)

Another thing would be to update once, run your physics simulation a bunch of times and then call render. Extra AI simulation, extra particles' calculation for your particle system.

These are just ideas on what you can do with the extra bandwidth rather than stalling the GPU/CPU (in the case of vsync) or displaying only a third (or less) of your intended frame (in the case of no vsync) otherwise known as tearing.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this